home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -serious- / programming / other / systracker_src / src / st_artl.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-28  |  80.8 KB  |  3,048 lines

  1. /***************************************************************************/
  2. /* st_artl.c - The Application Resource Tracker List (ARTL).               */
  3. /*                                                                         */
  4. /* Copyright © 1999-2000 Andrew Bell. All rights reserved.                 */
  5. /***************************************************************************/
  6.  
  7. #include "SysTracker_rev.h"
  8. #include "st_include.h"
  9. #include "st_protos.h"
  10. #include "st_strings.h"
  11.  
  12. /***************************************************************************/
  13. /* Data and defines */
  14. /***************************************************************************/
  15.  
  16. ULONG ARTL_TrackMode = TRACKMODE_LIBRARIES; /* Default */
  17. struct AppList *ARTL = NULL;
  18.  
  19. /* SysTracker <-> ATRL-Handler IPC */
  20.  
  21. BYTE ARTLInitSig_Running         = -1; /* Child process is running OK. */
  22. ULONG ARTLInitSigMask_Running    = 0;
  23. BYTE ARTLInitSig_NotRunning      = -1; /* Child process failed to start.  */
  24. ULONG ARTLInitSigMask_NotRunning = 0;
  25.  
  26. struct Process *ARTLProcess = NULL;
  27. struct MsgPort *ARTLProcessPort = NULL;
  28.  
  29. struct ARTLProcessMsg /* aka APM */
  30. {
  31.   struct Message apm_Msg;
  32.   LONG           apm_CmdID;
  33. };
  34.  
  35. enum /* The command set is fairly basic atm. */
  36. {
  37.   APM_CMDID_NOP = 0,
  38.   APM_CMDID_QUIT
  39. };
  40.  
  41. /***************************************************************************/
  42.  
  43. GPROTO BOOL ARTL_Init( void )
  44. {
  45.   /*********************************************************************
  46.    *
  47.    * ARTL_Init()
  48.    *
  49.    * This routine is called by the main SysTracker process. It is
  50.    * responsible for allocating all IPC related resources and invoking
  51.    * the ARTL handler (child) process. It will return TRUE for success
  52.    * else FALSE for failure.
  53.    *
  54.    *********************************************************************
  55.    *
  56.    */
  57.  
  58.   ARTLInitSig_Running = AllocSignal(-1);
  59.   if (ARTLInitSig_Running == -1) return FALSE;
  60.   ARTLInitSig_NotRunning = AllocSignal(-1);
  61.   if (ARTLInitSig_NotRunning == -1) return FALSE;
  62.  
  63.   /* Create the signal masks */
  64.  
  65.   ARTLInitSigMask_Running     = (1 << ARTLInitSig_Running);
  66.   ARTLInitSigMask_NotRunning  = (1 << ARTLInitSig_NotRunning);
  67.  
  68.   /* Some defines that will be moved to a header file later. */
  69.   
  70.   #define ARTL_PROCESS_NAME      "SysTracker's ARTL Handler"
  71.   #define ARTL_PROCESS_PRIORITY  -1
  72.   #define ARTL_PROCESS_STACKSIZE (1024 * 16)
  73.  
  74.   if (ARTLProcess = CreateNewProcTags(
  75.                       NP_StackSize, ARTL_PROCESS_STACKSIZE,
  76.                       NP_Name,      ARTL_PROCESS_NAME,
  77.                       NP_Priority,  ARTL_PROCESS_PRIORITY,
  78.                       NP_Entry,     &ARTL_HandlerProcess,
  79.                       TAG_DONE))
  80.   {
  81.     register ULONG SigsGot = 0;
  82.  
  83.     SigsGot = Wait(SIGBREAKF_CTRL_C |
  84.                    ARTLInitSigMask_Running |
  85.                    ARTLInitSigMask_NotRunning);
  86.  
  87.     if (SigsGot & ARTLInitSigMask_Running)    
  88.     {
  89.       /* OK, The process says it's running, if this is the
  90.          case then initialization was successful. Continue on
  91.          as normal. ARTLProcessPort will be valid. */
  92.     }
  93.     else if ((SigsGot & ARTLInitSigMask_NotRunning) ||
  94.              (SigsGot & SIGBREAKF_CTRL_C))
  95.     {
  96.       /* The process says it's going to quit, if this is the
  97.          case then initialization was not successful. */
  98.  
  99.       ARTLProcess = NULL;
  100.       return FALSE;
  101.     }
  102.   }
  103.   else return FALSE;
  104.  
  105.   return TRUE;
  106. }
  107.  
  108. GPROTO BOOL ARTL_Free( void )
  109. {
  110.   /*********************************************************************
  111.    *
  112.    * ARTL_Free()
  113.    *
  114.    * This routine will attempt to quit the ARTL process and free all
  115.    * allocated IPC related resources. It returns TRUE on success else
  116.    * FALSE on failure. Typically FALSE is returned when the ARTL
  117.    * handler process can't remove it's patches from the system.
  118.    *
  119.    *********************************************************************
  120.    *
  121.    */
  122.  
  123.   if (ARTLProcess && ARTLProcessPort)
  124.   {
  125.     register ULONG SigsGot = 0;
  126.  
  127.     if (!ARTL_SendSimpleAPMCmd(APM_CMDID_QUIT))
  128.       return FALSE;
  129.  
  130.     SigsGot = Wait(SIGBREAKF_CTRL_C |
  131.                    ARTLInitSigMask_Running |
  132.                    ARTLInitSigMask_NotRunning);
  133.  
  134.     if (SigsGot & ARTLInitSigMask_Running)
  135.     {
  136.       /* The process can't quit, probably because it can't remove
  137.          the patches. If this is the case then return FALSE, this will
  138.          make SysTracker go back into it's main loop. */
  139.  
  140.       return FALSE;
  141.     }
  142.     else if ((SigsGot & ARTLInitSigMask_NotRunning) ||
  143.              (SigsGot & SIGBREAKF_CTRL_C))
  144.     {
  145.       ARTLProcess = NULL;
  146.     }
  147.   }
  148.  
  149.   /* Free the signals */
  150.  
  151.   if (ARTLInitSig_Running != -1)
  152.   {
  153.     FreeSignal(ARTLInitSig_Running); ARTLInitSig_Running = -1;
  154.   }
  155.  
  156.   if (ARTLInitSig_NotRunning != -1)
  157.   {
  158.     FreeSignal(ARTLInitSig_NotRunning); ARTLInitSig_NotRunning = -1;
  159.   }
  160. }
  161.  
  162. GPROTO BOOL ARTL_SendSimpleAPMCmd( LONG CmdID )
  163. {
  164.   /*********************************************************************
  165.    *
  166.    * ARTL_SendSimpleAPMCmd()
  167.    *
  168.    * Send a simple command to the ARTL-Handler that requires no
  169.    * parameters. 
  170.    *
  171.    *********************************************************************
  172.    *
  173.    */
  174.  
  175.   struct ARTLProcessMsg APM;
  176.   memset(&APM, 0, sizeof(struct ARTLProcessMsg));
  177.   APM.apm_CmdID = CmdID;
  178.   return ARTL_SendAPM(&APM)
  179. }
  180.  
  181. GPROTO BOOL ARTL_SendAPM( struct ARTLProcessMsg *APM )
  182. {
  183.   /*********************************************************************
  184.    *
  185.    * ARTL_SendAPM()
  186.    *
  187.    * Send an ARTLProcessMsg to the ARTL-Handler process. This routine
  188.    * does all the dirty work like setting up the message header.
  189.    *
  190.    *********************************************************************
  191.    *
  192.    */
  193.  
  194.   struct MsgPort *TmpReplyPort = NULL;  
  195.   if (!APM || !ARTLProcessPort) return FALSE;
  196.  
  197.   if (TmpReplyPort = CreateMsgPort())
  198.   {
  199.     APM->apm_Msg.mn_Node.ln_Type = NT_MESSAGE;
  200.     APM->apm_Msg.mn_Length       = sizeof(struct ARTLProcessMsg);
  201.     APM->apm_Msg.mn_ReplyPort    = TmpReplyPort;
  202.     PutMsg(ARTLProcessPort, (struct Message *)APM);
  203.     Wait(1UL << TmpReplyPort->mp_SigBit);
  204.     DeleteMsgPort(TmpReplyPort);
  205.     return TRUE;
  206.   }
  207.   return FALSE;
  208. }
  209.  
  210. GPROTO struct AppList *ARTL_GetAppList( void )
  211. {
  212.   return ARTL;
  213. }
  214.  
  215. GPROTO void ARTL_Set_TrackMode( ULONG NewTrackMode )
  216. {
  217.   ARTL_TrackMode = NewTrackMode;
  218. }
  219.  
  220. GPROTO ULONG ARTL_Get_TrackMode( void )
  221. {
  222.   return ARTL_TrackMode;
  223. }
  224.  
  225. GPROTO BOOL ARTL_CheckProcSignals( ULONG SigsGot )
  226. {
  227.   /*********************************************************************
  228.    *
  229.    * ARTL_CheckProcSignals()
  230.    *
  231.    * This routine is called by the main SysTracker task when it receives
  232.    * some signals. This routine handles all of the ARTL process related
  233.    * signals. TRUE will be returned if SysTracker must quit.
  234.    *
  235.    *********************************************************************
  236.    *
  237.    */
  238.       
  239.   if (SigsGot & ARTLInitSigMask_NotRunning)
  240.   {
  241.     /* If we get this signal we must assume that something
  242.        has went wrong. */
  243.  
  244.     ARTLProcess = NULL; /* So ARTL_Free() knows the process is dead. */
  245.     return TRUE;
  246.   } 
  247.   return FALSE;
  248. }
  249.  
  250. /* ARTL handler process variables
  251.    ------------------------------
  252.    The ARTL AppList pointer belongs to the ARTL handler process,
  253.    and can *only* be access after the main SysTracker has received
  254.    the ARTLInitSig_Running signal. */
  255.  
  256. struct MsgPort *PatchPort = NULL;
  257. ULONG PMsgCnt = 0;
  258. BPTR DebugFH = 0;
  259.  
  260. GPROTO ULONG ARTL_GetPMsgCnt( void )
  261. {
  262.   return PMsgCnt;
  263. }
  264.  
  265. LPROTO LONG ARTL_HandlerProcess( void )
  266. {
  267.   /*********************************************************************
  268.    *
  269.    * ARTL_HandlerProc_Entry()
  270.    *
  271.    * This entire sub routine is an independent process that is launched
  272.    * by the main SysTracker process. This process is responsible for
  273.    * handling the PatchMsgs that arrive at the PatchPort, updating the
  274.    * main AppList tree per message. Because a constant stream of
  275.    * PatchMsgs may be arriving at the port, we use an independent
  276.    * process to handle the messages. This frees up the main SysTracker
  277.    * process, so it can handle the user's input, etc.
  278.    *
  279.    *********************************************************************
  280.    *
  281.    */
  282.  
  283.   /* Note: SysTracker is always compiled under a large code model, so
  284.            doesn't require A4 to be setup. */
  285.  
  286.   BOOL Success = FALSE; /* Assume failure */
  287.  
  288.   if (ATRL_InitHandlerDebug())
  289.   {
  290.     if ((PatchPort = CreateMsgPort()) &&
  291.         (ARTLProcessPort = CreateMsgPort()))
  292.     {
  293.       ULONG PatchPort_SigMask = 1UL << PatchPort->mp_SigBit;
  294.       ULONG ARTLProcessPort_SigMask = 1UL << ARTLProcessPort->mp_SigBit;
  295.       register struct PatchMsg *PMsg = NULL;
  296.       register struct ARTLProcessMsg *APM = NULL;
  297.  
  298.       if (ARTL = ARTL_AllocAL())
  299.       {
  300.         if (PATCH_Init())
  301.         {
  302.           Success = TRUE;
  303.           Signal((struct Task *)SysTrackerProcess, ARTLInitSigMask_Running);
  304.  
  305.           for (;;)
  306.           {
  307.             BOOL Running = TRUE;
  308.             ULONG SigEvent = 0;
  309.  
  310.             while (Running)
  311.             {
  312.               SigEvent = Wait(PatchPort_SigMask | ARTLProcessPort_SigMask);
  313.  
  314.               if (SigEvent & PatchPort_SigMask)
  315.               {
  316.                 while (PMsg =
  317.                    (struct PatchMsg *) GetMsg((struct MsgPort *) PatchPort))
  318.                 {                 
  319.                   PMsgCnt += 1;
  320.                   if (cfg_DebugMode) ARTL_PMsgDebug(PMsg);
  321.  
  322.                   switch(PMsg->pmsg_ID)
  323.                   {
  324.                     case PMSGID_OPENLIBRARY:
  325.                       ARTL_PushLibAN( ARTL, PMsg ); break;
  326.                     case PMSGID_CLOSELIBRARY:
  327.                       ARTL_PullLibAN( ARTL, PMsg ); break;
  328.                     case PMSGID_OPENDEVICE:
  329.                       ARTL_PushDevAN( ARTL, PMsg ); break;
  330.                     case PMSGID_CLOSEDEVICE:
  331.                       ARTL_PullDevAN( ARTL, PMsg ); break;
  332.                     case PMSGID_OPENFONT:
  333.                       ARTL_PushFontAN( ARTL, PMsg ); break;
  334.                     case PMSGID_CLOSEFONT:
  335.                       ARTL_PullFontAN( ARTL, PMsg ); break;
  336.                     case PMSGID_LOCK:
  337.                       ARTL_PushLockAN( ARTL, PMsg ); break;
  338.                     case PMSGID_UNLOCK:
  339.                       ARTL_PullLockAN( ARTL, PMsg ); break;
  340.                     case PMSGID_OPEN:
  341.                       ARTL_PushFileHandleAN( ARTL, PMsg ); break;
  342.                     case PMSGID_CLOSE:
  343.                       ARTL_PullFileHandleAN( ARTL, PMsg ); break;
  344.                     case PMSGID_OPENFROMLOCK:
  345.                       ARTL_PushFileHandleAN( ARTL, PMsg ); break;
  346.                     default: break;
  347.                   }
  348.  
  349.                   PATCH_DeletePatchMsg(PMsg);
  350.                 } /* while () */
  351.                 /* REMOVED: if (cfg_AutoUpdate) ACT_Main_Update();*/
  352.               }
  353.  
  354.               if (SigEvent & ARTLProcessPort_SigMask)
  355.               {
  356.                 /* The main ARTL process is communicating with us. */               
  357.  
  358.                 while (APM = (struct ARTLProcessMsg *) GetMsg(ARTLProcessPort))
  359.                 {
  360.                   switch(APM->apm_CmdID)
  361.                   {
  362.                     default:
  363.                     case APM_CMDID_NOP: break;
  364.                     case APM_CMDID_QUIT: Running = FALSE; break;
  365.                   }
  366.                   ReplyMsg((struct Message *)APM);
  367.                 }
  368.               }
  369.             } /* while () */
  370.  
  371.             if (PATCH_Free()) break;
  372.             else Signal((struct Task *)SysTrackerProcess,
  373.                   ARTLInitSigMask_Running);
  374.  
  375.           } /* for (;;) */                
  376.         }
  377.         ARTL_FreeAL(ARTL); ARTL = NULL;
  378.       }
  379.  
  380.       /* Free any pending messages on the PatchPort */  
  381.       while (PMsg = (struct PatchMsg *) GetMsg( (struct MsgPort *) PatchPort))
  382.         PATCH_DeletePatchMsg(PMsg);
  383.     }
  384.  
  385.     if (PatchPort)
  386.       DeletePort(PatchPort); PatchPort = NULL;
  387.  
  388.     if (ARTLProcessPort)
  389.       DeletePort(ARTLProcessPort); ARTLProcessPort = NULL;
  390.   }
  391.   ATRL_EndHandlerDebug();
  392.   ARTLProcess = NULL;
  393.  
  394.   Signal((struct Task *) SysTrackerProcess, ARTLInitSigMask_NotRunning);
  395.   return RETURN_OK;
  396. }
  397.  
  398. LPROTO BOOL ATRL_InitHandlerDebug( void )
  399. {
  400.   /*********************************************************************
  401.    *
  402.    * ATRL_InitHandlerDebug()
  403.    *
  404.    * Allocate the handler debugging resources.
  405.    *
  406.    *********************************************************************
  407.    *
  408.    */
  409.  
  410.   #define DEBUG_DEST "CON:0/11/640/60/ARTL_Handler_Debug_window/CLOSE"
  411.   /*#define DEBUG_DEST "Ram:SysTracker_debug.log"*/
  412.  
  413.   if (!cfg_DebugMode) return TRUE;
  414.   if (!(DebugFH = Open(DEBUG_DEST , MODE_NEWFILE))) return FALSE;
  415.  
  416.   return TRUE;
  417. }
  418.  
  419. LPROTO void ATRL_EndHandlerDebug( void )
  420. {
  421.   /*********************************************************************
  422.    *
  423.    * ATRL_EndHandlerDebug()
  424.    *
  425.    * Free the handler debugging resources.
  426.    *
  427.    *********************************************************************
  428.    *
  429.    */
  430.   
  431.   if (!cfg_DebugMode) return;
  432.   if (DebugFH)
  433.   {
  434.     Close(DebugFH); DebugFH = 0;
  435.   }
  436. }
  437.  
  438. LPROTO void ARTL_PMsgDebug( struct PatchMsg *PMsg )
  439. {
  440.   /*********************************************************************
  441.    *
  442.    * ARTL_PMsgDebug()
  443.    *
  444.    * Print some debug information about a PatchMsg structure.
  445.    *
  446.    *********************************************************************
  447.    *
  448.    */
  449.  
  450.   register UBYTE *LVOName = NULL;
  451.   register UBYTE *AppName = NULL;
  452.   struct AppNode *AN = NULL;
  453.   struct TrackerNode *TN =  NULL;
  454.  
  455.   if (!PMsg) return;
  456.  
  457.   AppName =
  458.      (PMsg->pmsg_CmdName ? PMsg->pmsg_CmdName : PMsg->pmsg_TaskName);
  459.  
  460.   if (!AppName || strlen(AppName) == 0) AppName = "(Unnamed task)";
  461.  
  462.   ARTL_LockAL(ARTL);
  463.  
  464.   AN = ARTL_FindAN_ViaTaskPtr(ARTL, PMsg->pmsg_TaskPtr);
  465.  
  466.   switch(PMsg->pmsg_ID)
  467.   {
  468.     case PMSGID_OPENLIBRARY:
  469.       FPrintf(DebugFH, "%-010.010s OpenLibrary(\"%s\", %ld)\n",
  470.         AppName, PMsg->pmsg_LibName, PMsg->pmsg_LibVer);
  471.       break;
  472.  
  473.     case PMSGID_OPENDEVICE:
  474.       FPrintf(DebugFH,
  475.         "%-010.010s OpenDevice(\"%s\", %ld, 0x%08lx, 0x%08lx)\n",
  476.         AppName, PMsg->pmsg_DevName,
  477.         PMsg->pmsg_DevUnitNum, PMsg->pmsg_DevIOReq, PMsg->pmsg_DevFlags);
  478.       break;
  479.  
  480.     case PMSGID_CLOSELIBRARY:
  481.       if (AN)
  482.       {
  483.         TN = ARTL_FindLibTN_ViaLibBase(
  484.           (struct List *) &AN->an_TrackerList, PMsg->pmsg_LibBase);
  485.       }
  486.       FPrintf(DebugFH,
  487.         "%-010.010s CloseLibrary($%08lx) [%s] AN=$%08lx TN=$%08lx\n",
  488.         AppName, PMsg->pmsg_LibBase, PMsg->pmsg_LibName, AN, TN);
  489.       break;
  490.  
  491.     case PMSGID_CLOSEDEVICE:
  492.       if (AN)
  493.       {
  494.         TN = ARTL_FindDevTN_ViaIOReq(
  495.           (struct List *) &AN->an_TrackerList, PMsg->pmsg_DevIOReq);
  496.       }
  497.       FPrintf(DebugFH,
  498.         "%-010.010s CloseDevice($%08lx) [%s] AN=$%08lx TN=$%08lx\n",
  499.         AppName, PMsg->pmsg_DevIOReq,
  500.         (TN ? TN->tn_DevName : "???"), AN, TN);
  501.       break;
  502.  
  503.     case PMSGID_OPENFONT:
  504.       FPrintf(DebugFH,
  505.         "%-010.010s OpenFont($%08lx) [%s/%ld]\n",
  506.         AppName, PMsg->pmsg_FontTextAttr,
  507.         PMsg->pmsg_FontName, (LONG) PMsg->pmsg_FontYSize);
  508.       break;
  509.  
  510.     case PMSGID_CLOSEFONT:
  511.       if (AN)
  512.       {
  513.         TN = ARTL_FindFontTN_ViaTextFont(
  514.           (struct List *) &AN->an_TrackerList, PMsg->pmsg_FontTextFont);
  515.       }
  516.       FPrintf(DebugFH,
  517.         "%-010.010s CloseFont($%08lx) [%s] AN=$%08lx TN=$%08lx\n",
  518.         AppName, PMsg->pmsg_FontTextFont,
  519.         (TN ? TN->tn_FontName : "???"), AN, TN);
  520.       break;
  521.  
  522.     case PMSGID_OPEN:
  523.       FPrintf(DebugFH,
  524.         "%-010.010s Open(%.256s,%ld) [FH=$%08lx]\n",
  525.         AppName, PMsg->pmsg_FHName, PMsg->pmsg_FHMode, PMsg->pmsg_FH);
  526.       break;
  527.  
  528.     case PMSGID_CLOSE:
  529.       FPrintf(DebugFH,
  530.         "%-010.010s Close($%08lx)\n",
  531.         AppName, PMsg->pmsg_FH);
  532.       break;
  533.  
  534.     case PMSGID_OPENFROMLOCK:
  535.       FPrintf(DebugFH,
  536.         "%-010.010s OpenFromLock($%08lx) [FH=$%08lx]\n",
  537.         AppName, PMsg->pmsg_Lock, PMsg->pmsg_Lock);
  538.       break;
  539.  
  540.     case PMSGID_LOCK:
  541.       FPrintf(DebugFH,
  542.         "%-010.010s Lock(%.256s,%ld) [LOCK=$%08lx]\n",
  543.         AppName, PMsg->pmsg_LockName,
  544.         PMsg->pmsg_LockMode, PMsg->pmsg_Lock);
  545.       break;
  546.  
  547.     case PMSGID_UNLOCK:
  548.       FPrintf(DebugFH,
  549.         "%-010.010s UnLock($%08lx)\n",
  550.         AppName, PMsg->pmsg_Lock);
  551.       break;
  552.  
  553.     default:
  554.       LVOName = "???";
  555.       break;
  556.   }
  557.   ARTL_UnlockAL(ARTL);
  558. }
  559.  
  560. LPROTO struct AppNode *ARTL_PushLibAN( struct AppList *AL,
  561.   struct PatchMsg *PMsg )
  562.   /*********************************************************************
  563.    *
  564.    * ARTL_PushLibAN()
  565.    *
  566.    * Append a library AppNode onto the main AppList (ARTL).
  567.    *
  568.    *********************************************************************
  569.    *
  570.    */
  571.  
  572.   register struct AppNode *AN;
  573.   register struct TrackerNode *TN;
  574.  
  575.   if (!PMsg->pmsg_LibBase) return NULL;
  576.  
  577.   ARTL_LockAL(AL);
  578.  
  579.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  580.   {       
  581.     /* OK, we're already tracking this App. We must now determine
  582.        if the library it's attempting to open is already on the
  583.        AppNode's TrackerNode list. If so, update the open count of
  584.        the existing TrackerNode else allocate a fresh TrackerNode. */
  585.  
  586.     if (TN = ARTL_FindLibTN_ViaLibName(
  587.               (struct List *) &AN->an_TrackerList, PMsg->pmsg_LibName))
  588.       TN->tn_OpenCnt += 1;
  589.     else if (TN = ARTL_CreateTN_ViaPMsg(PMsg))
  590.       ARTL_AddTNToTL(TN, (struct List *) &AN->an_TrackerList, ADDMODE_APPEND);
  591.     
  592.     /* Correct/update the task/process names. This comes in handy
  593.        if the application changes it's task/process name on the fly. */
  594.  
  595.     ARTL_SetANTaskName(AN, PMsg->pmsg_TaskName);
  596.     ARTL_SetANCmdName(AN, PMsg->pmsg_CmdName);    
  597.   } 
  598.   else if (AN = ARTL_CreateAN_ViaPMsg(PMsg))
  599.   {
  600.     /* At this point we've determined that the App is not being tracked,
  601.        because no AppNode exists for it. So we create one, using the
  602.        information found in the PatchMsg. Then link it onto the AppList. */
  603.     
  604.       ARTL_AddANToAL(AN, AL);
  605.   }
  606.   ARTL_UnlockAL(AL);
  607.   return AN;
  608. }
  609.  
  610. LPROTO void ARTL_PullLibAN( struct AppList *AL, struct PatchMsg *PMsg )
  611. {
  612.   /*********************************************************************
  613.    *
  614.    * ARTL_PullLibAN()
  615.    *
  616.    * Remove a library AppNode from the main AppList (ARTL).
  617.    *
  618.    *********************************************************************
  619.    *
  620.    */
  621.  
  622.   register struct AppNode *AN;
  623.  
  624.   ARTL_LockAL(AL);
  625.  
  626.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  627.   {
  628.     /* Now that we've found the AppNode associated with this call
  629.        to CloseLibrary(), we must scan the TrackerNode list for
  630.        the library that it's attempting to close. Once we find it,
  631.        we subtract it's open count, when this becomes zero, we can
  632.        unlink and delete it. If the TrackerNode list becomes empty,
  633.        then we can unlink and delete the AppNode also. */
  634.  
  635.     register struct TrackerNode *TN;
  636.  
  637.     if (PMsg->pmsg_LibBase)
  638.       TN = ARTL_FindLibTN_ViaLibBase(
  639.             (struct List *) &AN->an_TrackerList, PMsg->pmsg_LibBase);
  640.     else /* Find it by name */
  641.       TN = ARTL_FindLibTN_ViaLibName(
  642.             (struct List *) &AN->an_TrackerList, PMsg->pmsg_LibName);
  643.  
  644.     if (TN)
  645.     {     
  646.       TN->tn_OpenCnt -= 1;
  647.       
  648.       if (TN->tn_OpenCnt <= 0)
  649.       {
  650.         /* When the TrackerNode's open count becomes zero, we can mark
  651.            it as unused. But only if cfg_TrackResNotInUse is TRUE else
  652.            we delete the TrackerNode altogether. */
  653.  
  654.         if (cfg_TrackUnusedResources)
  655.         {
  656.           TN->tn_InUse = FALSE;
  657.  
  658.           if (ARTL_CountTNsInUse(&AN->an_TrackerList) == 0)
  659.           {
  660.             /* If this AppNode has freed all of it's resources then
  661.                remove the AppNode. */
  662.  
  663.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  664.           }
  665.         }
  666.         else /* Kill off the TrackerNode */
  667.         {
  668.           ARTL_UnlinkTN(TN); ARTL_FreeTN(TN);
  669.  
  670.           if (ARTL_CountTL(&AN->an_TrackerList, PMSGID_ALL) == 0)
  671.           {
  672.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  673.           }
  674.         }       
  675.       }
  676.     }
  677.   }
  678.   ARTL_UnlockAL(AL);
  679. }
  680.  
  681. LPROTO struct AppNode *ARTL_PushDevAN( struct AppList *AL,
  682.   struct PatchMsg *PMsg )
  683. {
  684.   /*********************************************************************
  685.    *
  686.    * ARTL_PushDevAN()
  687.    *
  688.    * Append a device AppNode onto the main AppList (ARTL).
  689.    *
  690.    *********************************************************************
  691.    *
  692.    */
  693.  
  694.   register struct AppNode *AN;
  695.   register struct TrackerNode *TN;
  696.  
  697.   if (!PMsg->pmsg_DevIOReq) return NULL;
  698.  
  699.   ARTL_LockAL(AL);
  700.  
  701.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  702.   {           
  703.     if (TN = ARTL_FindDevTN_ViaIOReq(
  704.               (struct List *) &AN->an_TrackerList, PMsg->pmsg_DevIOReq))
  705.       TN->tn_OpenCnt += 1;
  706.     else if (TN = ARTL_CreateTN_ViaPMsg(PMsg))
  707.       ARTL_AddTNToTL(TN, (struct List *) &AN->an_TrackerList, ADDMODE_APPEND);
  708.  
  709.     ARTL_SetANTaskName(AN, PMsg->pmsg_TaskName);
  710.     ARTL_SetANCmdName(AN, PMsg->pmsg_CmdName);    
  711.   } 
  712.   else if (AN = ARTL_CreateAN_ViaPMsg(PMsg))
  713.     ARTL_AddANToAL(AN, AL);
  714.   
  715.   ARTL_UnlockAL(AL);
  716.  
  717.   return AN;
  718. }
  719.  
  720. LPROTO void ARTL_PullDevAN( struct AppList *AL, struct PatchMsg *PMsg )
  721. {
  722.   /*********************************************************************
  723.    *
  724.    * ARTL_PullDevAN()
  725.    *
  726.    * Remove a library AppNode from the main AppList (ARTL).
  727.    *
  728.    *********************************************************************
  729.    *
  730.    */
  731.  
  732.   register struct AppNode *AN;
  733.   register struct TrackerNode *TN;
  734.  
  735.   ARTL_LockAL(AL);
  736.  
  737.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  738.   {
  739.     if (TN = ARTL_FindDevTN_ViaIOReq(
  740.               (struct List *) &AN->an_TrackerList, PMsg->pmsg_DevIOReq))
  741.     {     
  742.       TN->tn_OpenCnt -= 1;
  743.       
  744.       if (TN->tn_OpenCnt <= 0)
  745.       {
  746.         if (cfg_TrackUnusedResources)
  747.         {
  748.           TN->tn_InUse = FALSE;
  749.  
  750.           if (ARTL_CountTNsInUse(&AN->an_TrackerList) == 0)
  751.           {
  752.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  753.           }
  754.         }
  755.         else /* Kill off the TrackerNode */
  756.         {
  757.           ARTL_UnlinkTN(TN); ARTL_FreeTN(TN);
  758.  
  759.           if (ARTL_CountTL(&AN->an_TrackerList, PMSGID_ALL) == 0)
  760.           {
  761.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  762.           }
  763.         }       
  764.       }
  765.     }
  766.   }
  767.   ARTL_UnlockAL(AL);
  768. }
  769.  
  770. LPROTO struct AppNode *ARTL_PushFontAN( struct AppList *AL,
  771.   struct PatchMsg *PMsg )
  772. {
  773.   /*********************************************************************
  774.    *
  775.    * ARTL_PushFontAN()
  776.    *
  777.    *********************************************************************
  778.    *
  779.    */
  780.  
  781.   register struct AppNode *AN;
  782.  
  783.   if (!PMsg->pmsg_FontTextFont) return NULL;
  784.  
  785.   ARTL_LockAL(AL);
  786.  
  787.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  788.   {       
  789.     register struct TrackerNode *TN;
  790.  
  791.     if (TN = ARTL_FindFontTN_ViaTextFont(
  792.               (struct List *) &AN->an_TrackerList, PMsg->pmsg_FontTextFont))
  793.       TN->tn_OpenCnt += 1;
  794.     else if (TN = ARTL_CreateTN_ViaPMsg(PMsg))
  795.       ARTL_AddTNToTL(TN, (struct List *) &AN->an_TrackerList, ADDMODE_APPEND);
  796.  
  797.     ARTL_SetANTaskName(AN, PMsg->pmsg_TaskName);
  798.     ARTL_SetANCmdName(AN, PMsg->pmsg_CmdName);    
  799.   } 
  800.   else if (AN = ARTL_CreateAN_ViaPMsg(PMsg))
  801.     ARTL_AddANToAL(AN, AL);
  802.  
  803.   ARTL_UnlockAL(AL);
  804.   return AN;
  805. }
  806.  
  807. LPROTO void ARTL_PullFontAN( struct AppList *AL, struct PatchMsg *PMsg )
  808. {
  809.   /*********************************************************************
  810.    *
  811.    * ARTL_PullFontAN()
  812.    *
  813.    *********************************************************************
  814.    *
  815.    */
  816.  
  817.   register struct AppNode *AN;
  818.   register struct TrackerNode *TN;
  819.  
  820.   /* We're not interested in OpenFont()/OpenDiskFont() failures. */
  821.  
  822.   if (!PMsg->pmsg_FontTextFont) return;
  823.  
  824.   ARTL_LockAL(AL);
  825.  
  826.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  827.   {
  828.     if (TN = ARTL_FindFontTN_ViaTextFont(
  829.               (struct List *) &AN->an_TrackerList, PMsg->pmsg_FontTextFont))
  830.     {     
  831.       TN->tn_OpenCnt -= 1;      
  832.  
  833.       if (TN->tn_OpenCnt <= 0)
  834.       {
  835.         if (cfg_TrackUnusedResources)
  836.         {
  837.           TN->tn_InUse = FALSE;
  838.  
  839.           if (ARTL_CountTNsInUse(&AN->an_TrackerList) == 0)
  840.           {
  841.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  842.           }
  843.         }
  844.         else /* Kill off the TrackerNode */
  845.         {
  846.           ARTL_UnlinkTN(TN); ARTL_FreeTN(TN);
  847.  
  848.           if (ARTL_CountTL(&AN->an_TrackerList, PMSGID_ALL) == 0)
  849.           {
  850.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  851.           }
  852.         }       
  853.       }
  854.     }
  855.   } 
  856.   ARTL_UnlockAL(AL);
  857. }
  858.  
  859. LPROTO struct AppNode *ARTL_PushLockAN( struct AppList *AL,
  860.   struct PatchMsg *PMsg )
  861. {
  862.   /*********************************************************************
  863.    *
  864.    * ARTL_PushLockAN()
  865.    *
  866.    *********************************************************************
  867.    *
  868.    */
  869.  
  870.   register struct AppNode *AN;
  871.   register struct TrackerNode *TN;
  872.  
  873.   if (!PMsg->pmsg_Lock) return NULL;
  874.  
  875.   ARTL_LockAL(AL);
  876.  
  877.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  878.   {
  879.     /*if (TN = ARTL_FindLockTN_ViaLock((struct List *) &AN->an_TrackerList,
  880.               PMsg->pmsg_Lock))
  881.       TN->tn_OpenCnt += 1;
  882.     else*/
  883.     
  884.     if (TN = ARTL_CreateTN_ViaPMsg(PMsg))
  885.       ARTL_AddTNToTL(TN, (struct List *) &AN->an_TrackerList, ADDMODE_APPEND);
  886.  
  887.     ARTL_SetANTaskName(AN, PMsg->pmsg_TaskName);
  888.     ARTL_SetANCmdName(AN, PMsg->pmsg_CmdName);
  889.   } 
  890.   else if (AN = ARTL_CreateAN_ViaPMsg(PMsg))
  891.     ARTL_AddANToAL(AN, AL);
  892.  
  893.   ARTL_UnlockAL(AL);
  894.   return AN;
  895. }
  896.  
  897. LPROTO void ARTL_PullLockAN( struct AppList *AL, struct PatchMsg *PMsg )
  898. {
  899.   /*********************************************************************
  900.    *
  901.    * ARTL_PullLockAN()
  902.    *
  903.    *********************************************************************
  904.    *
  905.    */
  906.  
  907.   register struct AppNode *AN;
  908.   register struct TrackerNode *TN;
  909.  
  910.   ARTL_LockAL(AL);
  911.  
  912.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  913.   {
  914.     if (TN = ARTL_FindLockTN_ViaLock(
  915.               (struct List *) &AN->an_TrackerList, PMsg->pmsg_Lock))
  916.     {     
  917.       /*TN->tn_OpenCnt -= 1;  
  918.       if (TN->tn_OpenCnt <= 0)*/
  919.  
  920.       {
  921.         if (cfg_TrackUnusedResources)
  922.         {
  923.           TN->tn_InUse = FALSE;
  924.  
  925.           if (ARTL_CountTNsInUse(&AN->an_TrackerList) == 0)
  926.           {
  927.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  928.           }
  929.         }
  930.         else /* Kill off the TrackerNode */
  931.         {
  932.           ARTL_UnlinkTN(TN); ARTL_FreeTN(TN);
  933.  
  934.           if (ARTL_CountTL(&AN->an_TrackerList, PMSGID_ALL) == 0)
  935.           {
  936.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  937.           }
  938.         }       
  939.       }
  940.     }
  941.   }
  942.   ARTL_UnlockAL(AL);
  943. }
  944.  
  945. LPROTO struct AppNode *ARTL_PushFileHandleAN( struct AppList *AL,
  946.  struct PatchMsg *PMsg )
  947. {
  948.   /*********************************************************************
  949.    *
  950.    * ARTL_PushFileHandleAN()
  951.    *
  952.    *********************************************************************
  953.    *
  954.    */
  955.  
  956.   register struct AppNode *AN;
  957.   register struct TrackerNode *TN;
  958.  
  959.   if (!PMsg->pmsg_FH) return NULL;
  960.  
  961.   ARTL_LockAL(AL);
  962.  
  963.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  964.   {           
  965.     if (PMsg->pmsg_ID == PMSGID_OPENFROMLOCK)
  966.     {
  967.       /* Since OpenFromLock() will reqlinquish the lock, we need to
  968.          locate the TrackerNode that repesents that lock and kill
  969.          it. We also determine what pmsg_FHMode is here too. */
  970.       
  971.       if (TN = ARTL_FindLockTN_ViaLock(
  972.             (struct List *) &AN->an_TrackerList, PMsg->pmsg_Lock))
  973.       {
  974.         if (TN->tn_LockMode == SHARED_LOCK)
  975.           PMsg->pmsg_FHMode = MODE_OLDFILE;
  976.         else if (TN->tn_LockMode == EXCLUSIVE_LOCK)
  977.           PMsg->pmsg_FHMode = MODE_NEWFILE;
  978.  
  979.         if (TN->tn_CurDirName && !PMsg->pmsg_CurDirName)
  980.         {
  981.           if (!(PMsg->pmsg_CurDirName =
  982.                    PATCH_StrToVec(PMsg->pmsg_CurDirName)))
  983.           {
  984.             /* Note: Quick & dirty exit */ ARTL_UnlockAL(AL); return NULL;
  985.           }
  986.         }     
  987.         ARTL_UnlinkTN(TN); ARTL_FreeTN(TN);
  988.       }
  989.     }
  990.  
  991.     /*if (TN = ARTL_FindFileHandleTN_ViaFH(
  992.       (struct List *) &AN->an_TrackerList, PMsg->pmsg_FH))
  993.       TN->tn_OpenCnt += 1;
  994.     else*/ if (TN = ARTL_CreateTN_ViaPMsg(PMsg))
  995.       ARTL_AddTNToTL(TN, (struct List *) &AN->an_TrackerList, ADDMODE_APPEND);
  996.  
  997.     ARTL_SetANTaskName(AN, PMsg->pmsg_TaskName);
  998.     ARTL_SetANCmdName(AN, PMsg->pmsg_CmdName);    
  999.   } 
  1000.   else if (AN = ARTL_CreateAN_ViaPMsg(PMsg))
  1001.     ARTL_AddANToAL(AN, AL);
  1002.  
  1003.   ARTL_UnlockAL(AL);
  1004.  
  1005.   return AN;
  1006. }
  1007.  
  1008. LPROTO void ARTL_PullFileHandleAN( struct AppList *AL,
  1009.   struct PatchMsg *PMsg )
  1010. {
  1011.   /*********************************************************************
  1012.    *
  1013.    * ARTL_PullFileHandleAN()
  1014.    *
  1015.    *********************************************************************
  1016.    *
  1017.    */
  1018.  
  1019.   register struct AppNode *AN;
  1020.   register struct TrackerNode *TN;
  1021.  
  1022.   ARTL_LockAL(AL);
  1023.  
  1024.   if (AN = ARTL_FindAN_ViaTaskPtr(AL, PMsg->pmsg_TaskPtr))
  1025.   {
  1026.     if (TN = ARTL_FindFileHandleTN_ViaFH(
  1027.               (struct List *) &AN->an_TrackerList, PMsg->pmsg_FH))
  1028.     {     
  1029.       /*TN->tn_OpenCnt -= 1;
  1030.       
  1031.       if (TN->tn_OpenCnt <= 0)*/
  1032.       {
  1033.         if (cfg_TrackUnusedResources)
  1034.         {
  1035.           TN->tn_InUse = FALSE;
  1036.  
  1037.           if (ARTL_CountTNsInUse(&AN->an_TrackerList) == 0)
  1038.           {
  1039.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  1040.           }
  1041.         }
  1042.         else /* Kill off the TrackerNode */
  1043.         {
  1044.           ARTL_UnlinkTN(TN); ARTL_FreeTN(TN);
  1045.  
  1046.           if (ARTL_CountTL(&AN->an_TrackerList, PMSGID_ALL) == 0)
  1047.           {
  1048.             ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  1049.           }
  1050.         }
  1051.       }
  1052.     }
  1053.   } 
  1054.   ARTL_UnlockAL(AL);
  1055. }
  1056.  
  1057. /**** AppNode **************************************************************/
  1058.  
  1059. LPROTO struct AppList *ARTL_AllocAL( void )
  1060. {
  1061.   /*********************************************************************
  1062.    *
  1063.    * ARTL_AllocAL()
  1064.    *
  1065.    * Allocate an initialize an AppList structure.
  1066.    *
  1067.    *********************************************************************
  1068.    *
  1069.    */
  1070.  
  1071.   register struct AppList *AL;
  1072.   
  1073.   if (AL = MEM_AllocVec(AppList_SIZE))
  1074.   {
  1075.     NewList((struct List *) &AL->al_List);    
  1076.     InitSemaphore((struct SignalSemaphore *) &AL->al_Key);
  1077.   } 
  1078.   return AL;
  1079. }
  1080.  
  1081. LPROTO void ARTL_FreeAL( struct AppList *AL )
  1082. {
  1083.   /*********************************************************************
  1084.    *
  1085.    * ARTL_FreeAL()
  1086.    *
  1087.    * Free an AppList structure and it's associated allocations. Only
  1088.    * pass pointers created with ARTL_AllocAL().
  1089.    *
  1090.    *********************************************************************
  1091.    *
  1092.    */
  1093.  
  1094.   if (AL)
  1095.   { 
  1096.     ARTL_FlushAL(AL); MEM_FreeVec(AL);
  1097.   }
  1098. }
  1099.  
  1100. LPROTO void ARTL_LockAL( struct AppList *AL )
  1101. {
  1102.   /*********************************************************************
  1103.    *
  1104.    * ARTL_LockAL()
  1105.    *
  1106.    * Gain exclusive access to an AppList structure and it's AppNodes /
  1107.    * TrackerNodes.
  1108.    *
  1109.    *********************************************************************
  1110.    *
  1111.    */
  1112.  
  1113.   if (!AL) return;
  1114.  
  1115.   ObtainSemaphore((struct SignalSemaphore *) &AL->al_Key);
  1116. }
  1117.  
  1118. LPROTO void ARTL_UnlockAL( struct AppList *AL )
  1119. {
  1120.   /*********************************************************************
  1121.    *
  1122.    * ARTL_UnlockAL()
  1123.    *
  1124.    * Release the exclusive access obtained via ARTL_LockAL(), so other
  1125.    * tasks can access the AppList.
  1126.    *
  1127.    *********************************************************************
  1128.    *
  1129.    */
  1130.  
  1131.   if (!AL) return;
  1132.  
  1133.   ReleaseSemaphore((struct SignalSemaphore *) &AL->al_Key);
  1134. }
  1135.  
  1136. LPROTO void ARTL_FlushAL( struct AppList *AL )
  1137. {
  1138.   /*********************************************************************
  1139.    *
  1140.    * ARTL_FlushAL()
  1141.    *
  1142.    * Free all AppNodes in an AppList, but keep the AppList itself
  1143.    * intact and valid.
  1144.    *
  1145.    *********************************************************************
  1146.    *
  1147.    */
  1148.  
  1149.   register struct AppNode *AN, *TmpAN;
  1150.  
  1151.   if (!AL) return;
  1152.  
  1153.   ARTL_LockAL(AL);
  1154.   
  1155.   for (AN = (struct AppNode *) AL->al_List.lh_Head;
  1156.        AN->an_Node.ln_Succ;)
  1157.   {
  1158.     TmpAN = (struct AppNode *) AN->an_Node.ln_Succ;
  1159.     ARTL_FreeAN(AN); AN = TmpAN;
  1160.   }
  1161.  
  1162.   NewList((struct List *) &AL->al_List);  
  1163.  
  1164.   ARTL_UnlockAL(AL);
  1165. }
  1166.  
  1167. LPROTO struct AppNode *ARTL_CreateAN_ViaPMsg( struct PatchMsg *PMsg )
  1168. {
  1169.   /*********************************************************************
  1170.    *
  1171.    * ARTL_CreateAN_ViaPMsg()
  1172.    *
  1173.    * Create a fresh AppNode using a PatchMsg.
  1174.    * 
  1175.    *********************************************************************
  1176.    *
  1177.    */
  1178.  
  1179.   register struct AppNode *AN;
  1180.  
  1181.   if (AN = ARTL_AllocAN())
  1182.   {
  1183.     AN->an_TaskPtr = PMsg->pmsg_TaskPtr;
  1184.     AN->an_TaskType = PMsg->pmsg_TaskType;
  1185.     AN->an_LaunchType = PMsg->pmsg_LaunchType;
  1186.     AN->an_SegList = PMsg->pmsg_SegList;
  1187.     ARTL_SetANTaskName(AN, PMsg->pmsg_TaskName);
  1188.     ARTL_SetANCmdName(AN, PMsg->pmsg_CmdName); /* Note: OK to fail */
  1189.  
  1190.     if (AN->an_TaskName) /* Check the result of ARTL_SetTNTaskName() */
  1191.     {
  1192.       register struct TrackerNode *TN;
  1193.  
  1194.       if (TN = ARTL_CreateTN_ViaPMsg(PMsg))
  1195.       {
  1196.         ARTL_AddTNToTL(TN, (struct List *) &AN->an_TrackerList,
  1197.           ADDMODE_APPEND);
  1198.       }
  1199.       else
  1200.       {
  1201.         ARTL_FreeAN(AN); AN = NULL;
  1202.       }
  1203.     }
  1204.     else
  1205.     {
  1206.       ARTL_FreeAN(AN); AN = NULL;
  1207.     }
  1208.   }
  1209.   return AN;
  1210. }
  1211.  
  1212. LPROTO BOOL ARTL_AddANToAL( struct AppNode *InsAN, struct AppList *AL )
  1213. {
  1214.   /*********************************************************************
  1215.    *
  1216.    * ARTL_AddANToAL()
  1217.    *
  1218.    * Append an AppNode to an AppList.
  1219.    *
  1220.    *********************************************************************
  1221.    *
  1222.    */
  1223.  
  1224.   if (!InsAN || !AL) return FALSE;
  1225.   ARTL_LockAL(AL);
  1226.   AddTail((struct List *) &AL->al_List, (struct Node *) InsAN);
  1227.   ARTL_UnlockAL(AL);
  1228.   return TRUE;
  1229. }
  1230.  
  1231. LPROTO struct AppNode *ARTL_AllocAN( void )
  1232. {
  1233.   /*********************************************************************
  1234.    *
  1235.    * ARTL_AllocAN()
  1236.    *
  1237.    * Allocate an initialize an AppNode.
  1238.    *
  1239.    *********************************************************************
  1240.    *
  1241.    */
  1242.  
  1243.   register struct AppNode *AN;
  1244.  
  1245.   if (AN = MEM_AllocVec(AppNode_SIZE))
  1246.   {
  1247.     AN->an_Status = AN_STATUS_ALIVE;
  1248.     NewList((struct List *) &AN->an_TrackerList);
  1249.     DateStamp((struct DateStamp *) &AN->an_TrackDate);
  1250.   }
  1251.   return AN;  
  1252. }
  1253.  
  1254. LPROTO void ARTL_FreeAN( struct AppNode *AN )
  1255. {
  1256.   /*********************************************************************
  1257.    *
  1258.    * ARTL_FreeAN()
  1259.    *
  1260.    * Free an AppNode and it's associated resources. Only pass pointers
  1261.    * created with ARTL_AllocAN() or ARTL_CloneAN().
  1262.    *
  1263.    *********************************************************************
  1264.    *
  1265.    */
  1266.  
  1267.   if (AN)
  1268.   {
  1269.     ARTL_FreeTL((struct List *) &AN->an_TrackerList);
  1270.  
  1271.     if (AN->an_CmdName) MEM_FreeVec(AN->an_CmdName);
  1272.     if (AN->an_TaskName) MEM_FreeVec(AN->an_TaskName);
  1273.  
  1274.     MEM_FreeVec(AN);
  1275.   }
  1276. }
  1277.  
  1278. LPROTO struct AppNode *ARTL_CloneAN( struct AppNode *AN )
  1279. {
  1280.   /*********************************************************************
  1281.    *
  1282.    * ARTL_CloneAN()
  1283.    *
  1284.    * Clone an AppNode structure and it's entire TrackerNode list.
  1285.    *
  1286.    *********************************************************************
  1287.    *
  1288.    */
  1289.  
  1290.   register struct AppNode *NewAN;
  1291.   
  1292.   if (NewAN = MEM_AllocVec(AppNode_SIZE))
  1293.   {
  1294.     NewAN->an_Status = AN->an_Status;
  1295.     NewAN->an_TaskPtr = AN->an_TaskPtr;
  1296.     ARTL_SetANTaskName(NewAN, AN->an_TaskName);
  1297.     ARTL_SetANCmdName(NewAN, AN->an_CmdName); /* Note: OK to fail */
  1298.     NewAN->an_TrackDate.ds_Minute = AN->an_TrackDate.ds_Minute;
  1299.     NewAN->an_TrackDate.ds_Days = AN->an_TrackDate.ds_Days;
  1300.     NewAN->an_TrackDate.ds_Tick = AN->an_TrackDate.ds_Tick;
  1301.     NewAN->an_TaskType = AN->an_TaskType;
  1302.     NewAN->an_LaunchType = AN->an_LaunchType;
  1303.     NewAN->an_SegList = AN->an_SegList;
  1304.  
  1305.     /* Note: AN->an_CmdName may be NULL for tasks. */
  1306.  
  1307.     if (NewAN->an_TaskName) /* Check result of ARTL_SetTNTaskName() */
  1308.     {
  1309.       /* Here we clone the entire TrackerList */
  1310.  
  1311.       register struct TrackerNode *TN;
  1312.       
  1313.       NewList((struct List *) &NewAN->an_TrackerList);
  1314.  
  1315.       for (TN = (struct TrackerNode *) AN->an_TrackerList.lh_Head;
  1316.            TN->tn_Node.ln_Succ ;
  1317.            TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  1318.       {
  1319.         register struct TrackerNode *NewTN;
  1320.  
  1321.         if (NewTN = ARTL_CloneTN(TN))
  1322.         {
  1323.           ARTL_AddTNToTL(NewTN, (struct List *) &NewAN->an_TrackerList,
  1324.             ADDMODE_ALPHABETICALLY);
  1325.         }
  1326.         else
  1327.         {
  1328.           /* We've failed to construct the linked list. Abort the loop.
  1329.              ARTL_FreeAN() will clean up the mess for us. */
  1330.  
  1331.           ARTL_FreeAN(NewAN); NewAN = NULL; break;
  1332.         }
  1333.       } /* for(;;) */
  1334.     }
  1335.     else
  1336.     {     
  1337.       ARTL_FreeAN(NewAN); NewAN = NULL;
  1338.     }
  1339.   }
  1340.   return NewAN;
  1341. }
  1342.  
  1343. LPROTO struct AppNode *ARTL_FindAN_ViaTaskPtr( struct AppList *AL,
  1344.   struct Task *TaskPtrToFnd )
  1345. {   
  1346.   /*********************************************************************
  1347.    *
  1348.    * ARTL_FindAN_ViaTaskPtr()
  1349.    *
  1350.    * Find an AppNode in an AppList, using the TaskPtr field.
  1351.    *
  1352.    *********************************************************************
  1353.    *
  1354.    */
  1355.  
  1356.   register struct AppNode *AN;
  1357.  
  1358.   ARTL_LockAL(AL);
  1359.   for (AN = (struct AppNode *) AL->al_List.lh_Head;
  1360.        AN->an_Node.ln_Succ;
  1361.        AN = (struct AppNode *) AN->an_Node.ln_Succ)
  1362.   {
  1363.     if (TaskPtrToFnd == AN->an_TaskPtr)
  1364.     {
  1365.       ARTL_UnlockAL(AL); return AN;
  1366.     }
  1367.   }
  1368.   ARTL_UnlockAL(AL);
  1369.  
  1370.   return NULL;
  1371. }
  1372.  
  1373. LPROTO void ARTL_UnlinkAN( struct AppNode *AN )
  1374. {
  1375.   /*********************************************************************
  1376.    *
  1377.    * ARTL_UnlinkAN()
  1378.    *
  1379.    * Unlink an AppNode from an AppList. Usually this is called before
  1380.    * deallocation of the AppNode itself.
  1381.    * 
  1382.    *********************************************************************
  1383.    *
  1384.    */
  1385.  
  1386.   if ((AN->an_Node.ln_Succ == NULL) || (AN->an_Node.ln_Pred == NULL))
  1387.     return;
  1388.   Remove((struct Node *) AN);
  1389.   AN->an_Node.ln_Succ = NULL;
  1390.   AN->an_Node.ln_Pred = NULL;
  1391. }
  1392.  
  1393. LPROTO UWORD ARTL_UpdateANStatus( struct AppNode *AN )
  1394. {
  1395.   /*********************************************************************
  1396.    *
  1397.    * ARTL_UpdateANStatus()
  1398.    *
  1399.    * Update the status field (an_Status) of an AppNode structure. The
  1400.    * contents of an_Status is returned by this routine also.
  1401.    * 
  1402.    * Notes
  1403.    * -----
  1404.    *
  1405.    * This routine will give incorrect results if the task/process
  1406.    * modifies it's own name (i.e. Task->tc_Node.ln_Name) after
  1407.    * SysTracker created an AppNode for that task/process. This would
  1408.    * cause SysTracker to report the program as dead when in fact it's
  1409.    * really alive.
  1410.    *  
  1411.    * Notes on CLI & Shells
  1412.    * ---------------------
  1413.    *
  1414.    * Checking for the existances of a TaskPtr is fine for programs
  1415.    * launched from WB, but it doesn't really work for programs started
  1416.    * from CLI/Shell since they share the same TaskPtr as the CLI/Shell
  1417.    * process itself. I've added a work around that will check the
  1418.    * Process->pr_CLI->cli_Module to see if the command is still loaded.
  1419.    *
  1420.    *
  1421.    *********************************************************************
  1422.    *
  1423.    */
  1424.  
  1425.   register struct Process *ProcessPtr;
  1426.  
  1427.   Forbid();
  1428.  
  1429.   if (cfg_BeSystemLegal)
  1430.   {
  1431.     ProcessPtr = (struct Process *) FindTask(AN->an_TaskName);
  1432.   }
  1433.   else
  1434.   {
  1435.     if (R_IsTaskPtrValid(AN->an_TaskPtr))
  1436.     {
  1437.       ProcessPtr = (struct Process *) AN->an_TaskPtr;
  1438.     }
  1439.     else
  1440.     {
  1441.       ProcessPtr = NULL;
  1442.     }
  1443.   }
  1444.  
  1445.   if (ProcessPtr)
  1446.   {
  1447.     AN->an_Status = AN_STATUS_ALIVE;
  1448.  
  1449.     /* If it's CLI based, we must do a few more checks... */
  1450.  
  1451.     if (AN->an_LaunchType == LT_CLI)
  1452.     {   
  1453.       if (ProcessPtr &&
  1454.           (ProcessPtr->pr_Task.tc_Node.ln_Type == NT_PROCESS))
  1455.       {   
  1456.         register struct CommandLineInterface *CLI = NULL;
  1457.  
  1458.         AN->an_Status = AN_STATUS_ALIVE; /* Default */
  1459.         CLI = BADDR(ProcessPtr->pr_CLI);    
  1460.         if (AN->an_CmdName && CLI)
  1461.         {
  1462.           if (CLI->cli_Module)
  1463.           {
  1464.             /* Command is still loaded into CLI. */
  1465.         
  1466.             AN->an_Status = AN_STATUS_ALIVE;
  1467.           }
  1468.           else
  1469.           {
  1470.             /* Command has been unloaded from CLI (or it's detached
  1471.                itself from the CLI). */
  1472.         
  1473.             AN->an_Status = AN_STATUS_DEAD;
  1474.           }
  1475.         }
  1476.       }
  1477.     }
  1478.   }
  1479.   else
  1480.   {
  1481.     /* OK, we can't find the task. This means it's been removed
  1482.        or the task has changed it's tc_Node.ln_Name field. Either
  1483.        way, SysTracker considers it dead. */
  1484.     
  1485.     AN->an_Status = AN_STATUS_DEAD;
  1486.   }
  1487.  
  1488.   Permit();
  1489.  
  1490.   return AN->an_Status;
  1491. }
  1492.  
  1493. LPROTO UBYTE *ARTL_SetANTaskName( struct AppNode *AN, UBYTE *TaskName )
  1494. {
  1495.   /*********************************************************************
  1496.    *
  1497.    * ARTL_SetANTaskName()
  1498.    *
  1499.    * Set the AppNode->an_TaskName field of an AppNode structure.
  1500.    *
  1501.    *********************************************************************
  1502.    *
  1503.    */
  1504.  
  1505.   register UBYTE *FinalTaskName = NULL;
  1506.  
  1507.   if (!AN) return FALSE;
  1508.   
  1509.   if (AN->an_TaskName)
  1510.   {
  1511.     MEM_FreeVec(AN->an_TaskName); AN->an_TaskName = NULL;
  1512.   }
  1513.  
  1514.   if (!TaskName)
  1515.     FinalTaskName = MEM_StrToVec(STR_Get(SID_UNNAMED_BRACKET));
  1516.   else if (!TaskName[0])
  1517.     FinalTaskName = MEM_StrToVec(STR_Get(SID_EMPTY_NAME_BRACKET));
  1518.   else
  1519.     FinalTaskName = MEM_StrToVec(TaskName);
  1520.   
  1521.   AN->an_TaskName = FinalTaskName;
  1522.   return FinalTaskName;
  1523. }
  1524.  
  1525. LPROTO UBYTE *ARTL_SetANCmdName( struct AppNode *AN, UBYTE *CmdName )
  1526. {
  1527.   /*********************************************************************
  1528.    *
  1529.    * ARTL_SetANCmdName()
  1530.    * 
  1531.    * Set the AN->an_CmdName field of an AppNode structure.
  1532.    *
  1533.    *********************************************************************
  1534.    *
  1535.    */
  1536.  
  1537.   register UBYTE *FinalCmdName = NULL;
  1538.  
  1539.   if (!AN) return FALSE;
  1540.   
  1541.   if (AN->an_CmdName)
  1542.   {
  1543.     MEM_FreeVec(AN->an_CmdName); AN->an_CmdName = NULL;
  1544.   }
  1545.  
  1546.   /* If we can't get a decent process name, then leave the pointer
  1547.      NULL. This means the task name will be displayed/used instead. */
  1548.   
  1549.   if (!CmdName) FinalCmdName = NULL;
  1550.   else if (!CmdName[0]) FinalCmdName = NULL;
  1551.   else FinalCmdName = MEM_StrToVec(CmdName);
  1552.   
  1553.   AN->an_CmdName = FinalCmdName;
  1554.  
  1555.   return FinalCmdName;
  1556. }
  1557.  
  1558. LPROTO void ARTL_UpdateAL( struct AppList *AL )
  1559. {
  1560.   /*********************************************************************
  1561.    *
  1562.    * ARTL_UpdateAL()
  1563.    *
  1564.    * Refresh the Application GUI lister to reflect the current state
  1565.    * of the main AppList (ARTL).
  1566.    *
  1567.    *********************************************************************
  1568.    *
  1569.    */
  1570.  
  1571.   register struct AppNode *AN;
  1572.  
  1573.   GUI_Act_List_Clear(OID_MAIN_APPLIST);
  1574.   GUI_Act_List_Clear(OID_MAIN_TRACKERLIST);
  1575.  
  1576.   GUI_Set_List_Quiet(OID_MAIN_APPLIST, TRUE);
  1577.   ARTL_LockAL(AL);
  1578.  
  1579.   for (AN = (struct AppNode *) AL->al_List.lh_Head;
  1580.        AN->an_Node.ln_Succ;
  1581.        AN = (struct AppNode *) AN->an_Node.ln_Succ)
  1582.   {
  1583.     ARTL_UpdateANStatus(AN);
  1584.  
  1585.     if (cfg_ShowUnusedResources)
  1586.       GUI_Act_List_InsertABC(OID_MAIN_APPLIST, AN);
  1587.     else
  1588.       GUI_Act_List_InsertABC(OID_MAIN_APPLIST, AN);
  1589.   }
  1590.   ARTL_UnlockAL(AL);
  1591.   GUI_Set_List_Quiet(OID_MAIN_APPLIST, FALSE);
  1592. }
  1593.  
  1594. LPROTO BOOL ARTL_SaveALAsASCII( struct AppList *AL, UBYTE *DestFile,
  1595.   BOOL SaveAll )
  1596. {
  1597.   /*********************************************************************
  1598.    *
  1599.    * ARTL_SaveALAsASCII()
  1600.    *
  1601.    * Create and save a readable ASCII file of the main AppList (ARTL).
  1602.    *
  1603.    *********************************************************************
  1604.    *
  1605.    */
  1606.  
  1607.   register struct AppNode *AN;
  1608.   register BPTR OutFH;
  1609.   
  1610.   OutFH = Open(DestFile, MODE_NEWFILE);
  1611.  
  1612.   /* Take advantage of SetVBuf() if we're running under DOS v40.
  1613.  
  1614.      Note: v39 of DOS doesn't have the SetVBuf() code enabled so
  1615.            there's no point in checking for v39 too. */
  1616.  
  1617.   if (OutFH && (DOSBase->dl_lib.lib_Version >= 40))
  1618.   {
  1619.     if (SetVBuf(OutFH, NULL, BUF_FULL, IO_BUFFER_SIZE) != 0)
  1620.     {
  1621.       Close(OutFH); OutFH = 0;
  1622.     }   
  1623.   }
  1624.  
  1625.   if (OutFH)
  1626.   {
  1627.     struct DateStamp DS;
  1628.     UBYTE DateStrBuf[130];
  1629.     DateStamp((struct DateStamp *) &DS);
  1630.     
  1631.     if (R_DateStampToStr((struct DateStamp *) &DS,
  1632.           (UBYTE *) &DateStrBuf ))
  1633.     {
  1634.       register UBYTE *LineBuf = MEM_AllocVec(TEMP_BUFFER_SIZE);
  1635.  
  1636.       if (LineBuf)
  1637.       {
  1638.         FPrintf(OutFH, STR_Get(SID_GENERATED_WITH), VERS, &DateStrBuf);
  1639.  
  1640.         ARTL_LockAL(AL);
  1641.  
  1642.         for (AN = (struct AppNode *) AL->al_List.lh_Head;
  1643.              AN->an_Node.ln_Succ;
  1644.              AN = (struct AppNode *) AN->an_Node.ln_Succ)
  1645.         {         
  1646.           if (AN->an_Status == AN_STATUS_ALIVE)
  1647.           {         
  1648.             /* Note: When an AppNode is cloned, the TrackerNodes
  1649.                      are sorted alphabetically. */
  1650.  
  1651.             struct AppNode *ANClone = ARTL_CloneAN(AN);
  1652.  
  1653.             if (ANClone)
  1654.             {
  1655.               register ULONG LineLen = 0;
  1656.               register UBYTE *LinePtr = NULL;
  1657.  
  1658.               sprintf(LineBuf, STR_Get(SID_IS_USING),
  1659.                 AN->an_CmdName ? AN->an_CmdName : AN->an_TaskName);
  1660.               FPrintf(OutFH, LineBuf);
  1661.               LinePtr = LineBuf; LineLen = strlen(LineBuf) - 1;
  1662.               while (LineLen--) *LinePtr++ = '=';
  1663.               *LinePtr++ = '\n'; *LinePtr = 0;
  1664.               FPrintf(OutFH, LineBuf);
  1665.  
  1666.               /***********************************************************/
  1667.  
  1668.               ARTL_SaveAL_Libs(ANClone, OutFH, SaveAll);
  1669.               ARTL_SaveAL_Devs(ANClone, OutFH, SaveAll);
  1670.               ARTL_SaveAL_Fonts(ANClone, OutFH, SaveAll);
  1671.               ARTL_SaveAL_Locks(ANClone, OutFH, SaveAll);
  1672.               ARTL_SaveAL_FHs(ANClone, OutFH, SaveAll);
  1673.  
  1674.               /***********************************************************/
  1675.  
  1676.               FPrintf(OutFH, "\n");
  1677.  
  1678.               ARTL_FreeAN(ANClone); ANClone = NULL;
  1679.             }
  1680.           }
  1681.         } /* for(;;) */
  1682.         FPrintf(OutFH,
  1683. "*** SysTracker is Copyright © " YEAR " Andrew Bell. All rights reserved. ***\n"
  1684. "\n");
  1685.  
  1686.         ARTL_UnlockAL(AL);
  1687.         MEM_FreeVec(LineBuf);
  1688.       }
  1689.     }
  1690.     Close(OutFH);
  1691.   }
  1692.   return TRUE;
  1693. }
  1694.  
  1695. LPROTO BOOL ARTL_SaveAL_Libs( struct AppNode *ANClone, BPTR OutFH,
  1696.   BOOL SaveAll )
  1697. {
  1698.   register struct TrackerNode *TN;
  1699.   register ULONG AmtSaved = 0;
  1700.   register LONG HeaderPOF;
  1701.   
  1702.   HeaderPOF = Seek(OutFH, 0, OFFSET_CURRENT);
  1703.   if (HeaderPOF == -1) return FALSE;
  1704.   
  1705.   FPrintf(OutFH, "\n"
  1706.                  "    Libraries\n"
  1707.                  "    =========\n");                 
  1708.   for (TN = (struct TrackerNode *) ANClone->an_TrackerList.lh_Head;
  1709.        TN->tn_Node.ln_Succ;
  1710.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  1711.   {
  1712.     if (SaveAll || (!SaveAll && TN->tn_InUse))
  1713.     {
  1714.       if (TN->tn_ID == PMSGID_OPENLIBRARY)
  1715.       {
  1716.         FPrintf(OutFH, "    `%s'\n",
  1717.          (!TN->tn_LibName || !strlen(TN->tn_LibName)) ?
  1718.           "(unnamed library)" : TN->tn_LibName);
  1719.         AmtSaved++;
  1720.       }
  1721.     }
  1722.   }
  1723.  
  1724.   if (AmtSaved == 0)
  1725.     if (Seek(OutFH, HeaderPOF, OFFSET_BEGINNING) == -1)
  1726.       return FALSE;
  1727.  
  1728.   return TRUE;
  1729. }
  1730.  
  1731. LPROTO BOOL ARTL_SaveAL_Devs( struct AppNode *ANClone, BPTR OutFH,
  1732.   BOOL SaveAll )
  1733. {
  1734.   register struct TrackerNode *TN;
  1735.   register ULONG AmtSaved = 0;
  1736.   register LONG HeaderPOF;
  1737.   
  1738.   HeaderPOF = Seek(OutFH, 0, OFFSET_CURRENT);
  1739.   if (HeaderPOF == -1) return FALSE;
  1740.  
  1741.   FPrintf(OutFH, "\n"
  1742.                  "    Devices\n"
  1743.                  "    =======\n");
  1744.  
  1745.   for (TN = (struct TrackerNode *) ANClone->an_TrackerList.lh_Head;
  1746.        TN->tn_Node.ln_Succ;
  1747.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  1748.   {
  1749.     if (SaveAll || (!SaveAll && TN->tn_InUse))
  1750.     {
  1751.       if (TN->tn_ID == PMSGID_OPENDEVICE)
  1752.       {
  1753.         FPrintf(OutFH, "    `%s'\n",
  1754.           (!TN->tn_DevName || !strlen(TN->tn_DevName)) ?
  1755.           "(unnamed device)" : TN->tn_DevName);
  1756.  
  1757.         AmtSaved++;
  1758.       }
  1759.     }
  1760.   }
  1761.  
  1762.   if (AmtSaved == 0)
  1763.     if (Seek(OutFH, HeaderPOF, OFFSET_BEGINNING) == -1)
  1764.       return FALSE;
  1765.  
  1766.   return TRUE;
  1767. }
  1768.  
  1769. LPROTO BOOL ARTL_SaveAL_Fonts( struct AppNode *ANClone, BPTR OutFH,
  1770.   BOOL SaveAll )
  1771. {
  1772.   register struct TrackerNode *TN;
  1773.   register ULONG AmtSaved = 0;
  1774.   register LONG HeaderPOF;
  1775.   
  1776.   HeaderPOF = Seek(OutFH, 0, OFFSET_CURRENT);
  1777.   if (HeaderPOF == -1) return FALSE;
  1778.  
  1779.   FPrintf(OutFH, "\n"
  1780.                  "    Fonts\n"
  1781.                  "    =====\n");
  1782.   for (TN = (struct TrackerNode *) ANClone->an_TrackerList.lh_Head;
  1783.        TN->tn_Node.ln_Succ;
  1784.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  1785.   {
  1786.     if (SaveAll || (!SaveAll && TN->tn_InUse))
  1787.     {
  1788.       if (TN->tn_ID == PMSGID_OPENFONT)
  1789.       {
  1790.         FPrintf(OutFH, "    `%s'\n",
  1791.            (!TN->tn_FontName || !strlen(TN->tn_FontName)) ?
  1792.               "(unnamed font)" : TN->tn_FontName);
  1793.  
  1794.         AmtSaved++;
  1795.       }
  1796.     }
  1797.   }
  1798.  
  1799.   if (AmtSaved == 0)
  1800.     if (Seek(OutFH, HeaderPOF, OFFSET_BEGINNING) == -1)
  1801.       return FALSE;
  1802.  
  1803.   return TRUE;
  1804. }
  1805.  
  1806. LPROTO BOOL ARTL_SaveAL_Locks( struct AppNode *ANClone, BPTR OutFH,
  1807.   BOOL SaveAll )
  1808. {
  1809.   register struct TrackerNode *TN;
  1810.   register ULONG AmtSaved = 0;
  1811.   register LONG HeaderPOF;
  1812.   
  1813.   HeaderPOF = Seek(OutFH, 0, OFFSET_CURRENT);
  1814.   if (HeaderPOF == -1) return FALSE;
  1815.  
  1816.   FPrintf(OutFH, "\n"
  1817.                  "    Locks\n"
  1818.                  "    =====\n");
  1819.  
  1820.   for (TN = (struct TrackerNode *) ANClone->an_TrackerList.lh_Head;
  1821.        TN->tn_Node.ln_Succ;
  1822.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  1823.   {
  1824.     if (TN->tn_ID == PMSGID_LOCK)
  1825.     {
  1826.       if (SaveAll || (!SaveAll && TN->tn_InUse))
  1827.       {
  1828.         FPrintf(OutFH, "    `%s'\n",
  1829.           (!TN->tn_LockName || !strlen(TN->tn_LockName)) ?
  1830.            "(unnamed lock)" : TN->tn_LockName);
  1831.  
  1832.         AmtSaved++;
  1833.       }
  1834.     }
  1835.   }
  1836.  
  1837.   if (AmtSaved == 0)
  1838.     if (Seek(OutFH, HeaderPOF, OFFSET_BEGINNING) == -1)
  1839.       return FALSE;
  1840.  
  1841.   return TRUE;
  1842. }
  1843.  
  1844. LPROTO BOOL ARTL_SaveAL_FHs( struct AppNode *ANClone, BPTR OutFH,
  1845.   BOOL SaveAll )
  1846. {
  1847.   register struct TrackerNode *TN;
  1848.   register ULONG AmtSaved = 0;
  1849.   register LONG HeaderPOF;
  1850.   
  1851.   HeaderPOF = Seek(OutFH, 0, OFFSET_CURRENT);
  1852.   if (HeaderPOF == -1) return FALSE;
  1853.  
  1854.   FPrintf(OutFH, "\n"
  1855.                  "    Files accessed\n"
  1856.                  "    ==============\n");
  1857.  
  1858.   for (TN = (struct TrackerNode *) ANClone->an_TrackerList.lh_Head;
  1859.        TN->tn_Node.ln_Succ;
  1860.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  1861.   {
  1862.     if (SaveAll || (!SaveAll && TN->tn_InUse))
  1863.     {
  1864.       if ((TN->tn_ID == PMSGID_OPEN) ||
  1865.           (TN->tn_ID == PMSGID_OPENFROMLOCK))
  1866.       {
  1867.         FPrintf(OutFH, "    `%s'\n",
  1868.           (!TN->tn_FHName || !strlen(TN->tn_FHName)) ?
  1869.           "(unnamed file)" : TN->tn_FHName);
  1870.  
  1871.         AmtSaved++;
  1872.       }
  1873.     }
  1874.   }
  1875.  
  1876.   if (AmtSaved == 0)
  1877.     if (Seek(OutFH, HeaderPOF, OFFSET_BEGINNING) == -1)
  1878.       return FALSE;
  1879.  
  1880.   return TRUE;
  1881. }
  1882.  
  1883. LPROTO LONG ARTL_GetANListIndex_ViaTaskPtr( struct Task *TaskPtr )
  1884. {
  1885.   /*********************************************************************
  1886.    *
  1887.    * ARTL_GetANListIndex_ViaTaskPtr()
  1888.    * 
  1889.    * Find an AppNode in the main GUI lister via a TaskPtr. Remember
  1890.    * that the GUI list uses cloned AppNodes!
  1891.    *
  1892.    *********************************************************************
  1893.    *
  1894.    */
  1895.  
  1896.   register LONG Index = 0;
  1897.  
  1898.   for (Index = 0 ;; Index++)
  1899.   {
  1900.     struct AppNode *AN = GUI_Get_List_Entry(OID_MAIN_APPLIST, Index);
  1901.     if (!AN) break;
  1902.     if (TaskPtr == AN->an_TaskPtr) return Index;
  1903.   }
  1904.   return -1;
  1905. }
  1906.  
  1907. GPROTO LONG ARTL_ClearDeadANs( struct AppList *AL )
  1908. {
  1909.   /*********************************************************************
  1910.    *
  1911.    * ARTL_ClearDeadANs()
  1912.    * 
  1913.    * Delete those AppNodes in an AppList that no longer have a task
  1914.    * associated with it.
  1915.    *
  1916.    *********************************************************************
  1917.    *
  1918.    */
  1919.  
  1920.   register LONG DeadANCnt = 0;
  1921.   register struct AppNode *AN, *NextAN;
  1922.  
  1923.   ARTL_LockAL(AL);
  1924.  
  1925.   for (AN = (struct AppNode *) AL->al_List.lh_Head;
  1926.        AN->an_Node.ln_Succ;)
  1927.   {
  1928.     NextAN = (struct AppNode *) AN->an_Node.ln_Succ;
  1929.  
  1930.     if (ARTL_UpdateANStatus(AN) == AN_STATUS_DEAD)
  1931.     {
  1932.       ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  1933.       DeadANCnt++;
  1934.     }
  1935.     
  1936.     AN = NextAN;
  1937.   }
  1938.   ARTL_UnlockAL(AL);
  1939.   ARTL_UpdateAL(AL);
  1940.   
  1941.   return DeadANCnt;
  1942. }
  1943.  
  1944. GPROTO ULONG ARTL_ClearUnusedANs( struct AppList *AL )
  1945. {
  1946.   /*********************************************************************
  1947.    *
  1948.    * ARTL_ClearUnusedANs()
  1949.    *
  1950.    * Clear all AppNodes that don't have any allocated resources.
  1951.    *
  1952.    *********************************************************************
  1953.    *
  1954.    */
  1955.  
  1956.   register LONG FreedANCnt = 0;
  1957.   register struct AppNode *AN, *NextAN;
  1958.  
  1959.   ARTL_LockAL(AL);
  1960.  
  1961.   for (AN = (struct AppNode *) AL->al_List.lh_Head;
  1962.        AN->an_Node.ln_Succ;)
  1963.   {
  1964.     NextAN = (struct AppNode *) AN->an_Node.ln_Succ;
  1965.  
  1966.     ARTL_ClearUnusedTNs(&AN->an_TrackerList);
  1967.  
  1968.     if (ARTL_CountTNsInUse(&AN->an_TrackerList) == 0)
  1969.     {
  1970.       ARTL_UnlinkAN(AN); ARTL_FreeAN(AN);
  1971.       FreedANCnt++;
  1972.     }   
  1973.     AN = NextAN;
  1974.   }
  1975.   ARTL_UnlockAL(AL);
  1976.   ARTL_UpdateAL(AL);
  1977.   
  1978.   return FreedANCnt;
  1979. }
  1980.  
  1981. /**** TrackerNode **********************************************************/
  1982.  
  1983. LPROTO struct TrackerNode *ARTL_CreateTN_ViaPMsg( struct PatchMsg *PMsg )
  1984. {
  1985.   /*********************************************************************
  1986.    *
  1987.    * ARTL_CreateTN_ViaPMsg()
  1988.    *
  1989.    * Create a TrackerNode using a PatchMsg.
  1990.    *
  1991.    *********************************************************************
  1992.    *
  1993.    */
  1994.  
  1995.   register struct TrackerNode *TN;
  1996.   register BOOL Success = FALSE;
  1997.  
  1998.   if (TN = ARTL_AllocTN())
  1999.   {
  2000.     UBYTE TmpBuf[256];
  2001.  
  2002.     TN->tn_OpenCnt = 1; /* The creation of this TN implies that something
  2003.                            has opened it. */
  2004.     TN->tn_InUse = TRUE; /* It also implies that something is using it. */
  2005.  
  2006.     switch(PMsg->pmsg_ID)
  2007.     {
  2008.       case PMSGID_OPENLIBRARY:
  2009.         TN->tn_ID = PMSGID_OPENLIBRARY;
  2010.         TN->tn_LibName = MEM_StrToVec(PMsg->pmsg_LibName);
  2011.         TN->tn_LibVer = PMsg->pmsg_LibVer;
  2012.         TN->tn_LibBase = PMsg->pmsg_LibBase;
  2013.         if (TN->tn_LibName) Success = TRUE;
  2014.         break;
  2015.  
  2016.       case PMSGID_OPENDEVICE:
  2017.         TN->tn_ID = PMSGID_OPENDEVICE;
  2018.         TN->tn_DevName = MEM_StrToVec(PMsg->pmsg_DevName);
  2019.         TN->tn_DevUnitNum = PMsg->pmsg_DevUnitNum;
  2020.         TN->tn_DevIOReq = PMsg->pmsg_DevIOReq;
  2021.         TN->tn_DevFlags = PMsg->pmsg_DevFlags;
  2022.         if (TN->tn_DevName) Success = TRUE;
  2023.         break;
  2024.  
  2025.       case PMSGID_OPENFONT:
  2026.         TN->tn_ID = PMSGID_OPENFONT;
  2027.         TN->tn_FontTextAttr = PMsg->pmsg_FontTextAttr;
  2028.         TN->tn_FontTextFont = PMsg->pmsg_FontTextFont;
  2029.         sprintf((UBYTE *)&TmpBuf, "%s/%lu",
  2030.           PMsg->pmsg_FontName, (ULONG) PMsg->pmsg_FontYSize);
  2031.         TN->tn_FontName = MEM_StrToVec((UBYTE *)&TmpBuf);
  2032.         TN->tn_FontYSize = PMsg->pmsg_FontYSize;
  2033.         TN->tn_FontStyle = PMsg->pmsg_FontStyle;
  2034.         TN->tn_FontFlags = PMsg->pmsg_FontFlags;
  2035.         if (TN->tn_FontName) Success = TRUE;
  2036.         break;
  2037.  
  2038.       case PMSGID_LOCK:
  2039.         TN->tn_ID = PMSGID_LOCK;
  2040.         TN->tn_Lock = PMsg->pmsg_Lock;
  2041.         TN->tn_LockMode = PMsg->pmsg_LockMode;
  2042.         TN->tn_LockName = MEM_StrToVec(PMsg->pmsg_LockName);
  2043.         if (TN->tn_LockName) Success = TRUE;
  2044.         break;
  2045.  
  2046.       case PMSGID_OPEN:
  2047.         TN->tn_ID = PMSGID_OPEN;
  2048.         TN->tn_FH = PMsg->pmsg_FH;
  2049.         TN->tn_FHMode = PMsg->pmsg_FHMode;
  2050.         TN->tn_FHName = MEM_StrToVec(PMsg->pmsg_FHName);
  2051.         if (TN->tn_FHName) Success = TRUE;
  2052.         break;
  2053.  
  2054.       case PMSGID_OPENFROMLOCK:
  2055.         TN->tn_ID = PMSGID_OPENFROMLOCK;
  2056.         TN->tn_Lock = PMsg->pmsg_Lock;
  2057.         TN->tn_FH = PMsg->pmsg_FH;
  2058.         TN->tn_FHName = MEM_StrToVec(PMsg->pmsg_FHName);
  2059.         if (TN->tn_FHName) Success = TRUE;
  2060.         break;
  2061.  
  2062.       default: break;
  2063.     }
  2064.  
  2065.     if (!Success)
  2066.     {     
  2067.       ARTL_FreeTN(TN); TN = NULL;
  2068.     }
  2069.     else
  2070.     {
  2071.       /* If this is a file related TrackerNode, build the full path. */
  2072.       
  2073.       if (!ATRL_BuildTNPath(TN))
  2074.       {
  2075.         ARTL_FreeTN(TN); TN = NULL;
  2076.       }
  2077.     }
  2078.   }
  2079.   return TN;
  2080. }
  2081.  
  2082. LPROTO BOOL ARTL_AddTNToTL(
  2083.   struct TrackerNode *InsTN, struct List *TL, ULONG AddMode )
  2084. {
  2085.   /*********************************************************************
  2086.    *
  2087.    * ARTL_AddTNToTL()
  2088.    *
  2089.    * Add a TrackerNode to a TrackerList.
  2090.    *
  2091.    *********************************************************************
  2092.    *
  2093.    */
  2094.  
  2095.   if (!InsTN || !TL) return FALSE;
  2096.  
  2097.   if (AddMode == ADDMODE_ALPHABETICALLY)
  2098.   {
  2099.     register struct TrackerNode *TN;
  2100.  
  2101.     for (TN = (struct TrackerNode *) TL->lh_Head;
  2102.          TN->tn_Node.ln_Succ;
  2103.          TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2104.     {
  2105.       register LONG r;
  2106.       
  2107.       if ((TN->tn_ID == PMSGID_OPENLIBRARY) &&
  2108.           (InsTN->tn_ID == PMSGID_OPENLIBRARY))
  2109.         r = Stricmp(TN->tn_LibName, InsTN->tn_LibName);
  2110.       else if ((TN->tn_ID == PMSGID_OPENDEVICE) &&
  2111.               (InsTN->tn_ID == PMSGID_OPENDEVICE))
  2112.         r = Stricmp(TN->tn_DevName, InsTN->tn_DevName);
  2113.       else if ((TN->tn_ID == PMSGID_OPENFONT) &&
  2114.               (InsTN->tn_ID == PMSGID_OPENFONT))
  2115.         r = Stricmp(TN->tn_FontName, InsTN->tn_FontName);
  2116.       else r = -1;
  2117.  
  2118.       if (r >= 0)
  2119.       {
  2120.         Insert((struct List *) &TL,
  2121.                (struct Node *) InsTN,
  2122.                (struct Node *) TN->tn_Node.ln_Pred);
  2123.  
  2124.         return TRUE;
  2125.       }
  2126.     }
  2127.     AddTail(TL, (struct Node *) InsTN); 
  2128.   }
  2129.   else
  2130.     AddTail(TL, (struct Node *) InsTN);
  2131.  
  2132.   return TRUE;
  2133. }
  2134.  
  2135. LPROTO struct TrackerNode *ARTL_AllocTN( void )
  2136. {
  2137.   /*********************************************************************
  2138.    *
  2139.    * ARTL_AllocTN()
  2140.    *
  2141.    * Allocate and initialize a TrackerNode structure.
  2142.    *
  2143.    *********************************************************************
  2144.    *
  2145.    */
  2146.  
  2147.   register struct TrackerNode *TN;
  2148.  
  2149.   if (TN = MEM_AllocVec(TrackerNode_SIZE))
  2150.   {
  2151.     DateStamp((struct DateStamp *) &TN->tn_TrackDate);
  2152.   } 
  2153.   return TN;
  2154. }
  2155.  
  2156. LPROTO void ARTL_FreeTN( struct TrackerNode *TN )
  2157. {
  2158.   /*********************************************************************
  2159.    *
  2160.    * ARTL_FreeTN()
  2161.    *
  2162.    * Free a TrackerNode structure and it's associated resources. Only
  2163.    * pass pointers from ARTL_AllocTN() or ARTL_CloneTN().
  2164.    *
  2165.    *********************************************************************
  2166.    *
  2167.    */
  2168.  
  2169.   if (TN)
  2170.   {
  2171.     if (TN->tn_LibName) MEM_FreeVec(TN->tn_LibName);
  2172.     if (TN->tn_DevName) MEM_FreeVec(TN->tn_DevName);
  2173.     if (TN->tn_FontName) MEM_FreeVec(TN->tn_FontName);
  2174.     if (TN->tn_FHName) MEM_FreeVec(TN->tn_FHName);
  2175.     if (TN->tn_LockName) MEM_FreeVec(TN->tn_LockName);
  2176.     if (TN->tn_CurDirName) MEM_FreeVec(TN->tn_CurDirName);
  2177.     MEM_FreeVec(TN);
  2178.   }
  2179. }
  2180.  
  2181. LPROTO struct TrackerNode *ARTL_CloneTN( struct TrackerNode *TN )
  2182. {
  2183.   /*********************************************************************
  2184.    *
  2185.    * ARTL_CloneTN()
  2186.    *
  2187.    * Clone a TrackerNode and it's associated resources.
  2188.    *
  2189.    *********************************************************************
  2190.    *
  2191.    */
  2192.  
  2193.   register struct TrackerNode *NewTN;
  2194.   register BOOL Success = FALSE; /* Assume an error will happen */
  2195.  
  2196.   if (NewTN = MEM_AllocVec(TrackerNode_SIZE))
  2197.   {
  2198.     NewTN->tn_ID = TN->tn_ID;
  2199.     NewTN->tn_OpenCnt = TN->tn_OpenCnt;
  2200.     NewTN->tn_InUse = TN->tn_InUse;
  2201.     NewTN->tn_TrackDate.ds_Minute = TN->tn_TrackDate.ds_Minute;
  2202.     NewTN->tn_TrackDate.ds_Days = TN->tn_TrackDate.ds_Days;
  2203.     NewTN->tn_TrackDate.ds_Tick = TN->tn_TrackDate.ds_Tick;
  2204.  
  2205.     switch(NewTN->tn_ID)
  2206.     {
  2207.       case PMSGID_OPENLIBRARY:
  2208.         NewTN->tn_LibName = MEM_StrToVec(TN->tn_LibName);
  2209.         NewTN->tn_LibVer = TN->tn_LibVer;
  2210.         NewTN->tn_LibBase = TN->tn_LibBase;
  2211.         if (NewTN->tn_LibName) Success = TRUE;
  2212.         break;
  2213.  
  2214.       case PMSGID_OPENDEVICE:
  2215.         NewTN->tn_DevName = MEM_StrToVec(TN->tn_DevName); 
  2216.         NewTN->tn_DevUnitNum = TN->tn_DevUnitNum;
  2217.         NewTN->tn_DevIOReq = TN->tn_DevIOReq;
  2218.         NewTN->tn_DevFlags = TN->tn_DevFlags;
  2219.         if (NewTN->tn_DevName) Success = TRUE;
  2220.         break;
  2221.  
  2222.       case PMSGID_OPENFONT:
  2223.         NewTN->tn_ID = TN->tn_ID;
  2224.         NewTN->tn_FontTextAttr = TN->tn_FontTextAttr;
  2225.         NewTN->tn_FontTextFont = TN->tn_FontTextFont;
  2226.         NewTN->tn_FontName = MEM_StrToVec(TN->tn_FontName);
  2227.         NewTN->tn_FontYSize = TN->tn_FontYSize;
  2228.         NewTN->tn_FontStyle = TN->tn_FontStyle;
  2229.         NewTN->tn_FontFlags = TN->tn_FontFlags;
  2230.         if (NewTN->tn_FontName) Success = TRUE;
  2231.         break;
  2232.  
  2233.       case PMSGID_LOCK:
  2234.         NewTN->tn_ID = TN->tn_ID;
  2235.         NewTN->tn_Lock = TN->tn_Lock;
  2236.         NewTN->tn_LockMode = TN->tn_LockMode;
  2237.         NewTN->tn_LockName = MEM_StrToVec(TN->tn_LockName);
  2238.         if (TN->tn_CurDirName)
  2239.           if (!(NewTN->tn_CurDirName = MEM_StrToVec(TN->tn_CurDirName)))
  2240.             break;
  2241.  
  2242.         if (NewTN->tn_LockName) Success = TRUE;
  2243.         break;
  2244.  
  2245.       case PMSGID_OPEN:
  2246.         NewTN->tn_ID = TN->tn_ID;
  2247.         NewTN->tn_FH = TN->tn_FH;
  2248.         NewTN->tn_FHMode = TN->tn_FHMode;
  2249.         NewTN->tn_FHName = MEM_StrToVec(TN->tn_FHName);
  2250.         if (TN->tn_CurDirName)
  2251.           if (!(TN->tn_CurDirName = MEM_StrToVec(TN->tn_CurDirName)))
  2252.             break;
  2253.  
  2254.         if (NewTN->tn_FHName) Success = TRUE;
  2255.         break;
  2256.  
  2257.       case PMSGID_OPENFROMLOCK:
  2258.         NewTN->tn_ID = NewTN->tn_ID;
  2259.         NewTN->tn_Lock = TN->tn_Lock;
  2260.         NewTN->tn_FH = TN->tn_FH;
  2261.         NewTN->tn_FHName = MEM_StrToVec(TN->tn_FHName);
  2262.         if (TN->tn_CurDirName)
  2263.           if (!(TN->tn_CurDirName = MEM_StrToVec(TN->tn_CurDirName)))
  2264.             break;
  2265.         if (NewTN->tn_FHName) Success = TRUE;
  2266.         break;
  2267.     }
  2268.   } 
  2269.   if (!Success)
  2270.   {
  2271.     ARTL_FreeTN(NewTN); NewTN = NULL;
  2272.   }
  2273.   return NewTN;
  2274. }
  2275.  
  2276. LPROTO BOOL ATRL_BuildTNPath( struct TrackerNode *TN )
  2277. {
  2278.   /*********************************************************************
  2279.    *
  2280.    * ATRL_BuildTNPath()
  2281.    *
  2282.    * The routine makes sure that the Name field of a file related
  2283.    * TrackerNode is a full path. This is done by joining the
  2284.    * TN->tn_CurDirName and name fields.
  2285.    *
  2286.    * Normally this routine is called after a TrackerNode has been
  2287.    * freshly created.
  2288.    *
  2289.    *********************************************************************
  2290.    *
  2291.    */
  2292.  
  2293.   #define TMP_BUF_LEN 512
  2294.  
  2295.   UBYTE **NamePart = NULL;
  2296.   UBYTE TmpPath[TMP_BUF_LEN + 2];
  2297.  
  2298.   if (!TN) return FALSE;
  2299.   if (!TN->tn_CurDirName) return TRUE;
  2300.     
  2301.   switch(TN->tn_ID)
  2302.   {
  2303.     case PMSGID_OPEN:
  2304.       NamePart = (UBYTE **) &TN->tn_FHName;   break;
  2305.     case PMSGID_OPENFROMLOCK:
  2306.       NamePart = (UBYTE **) &TN->tn_FHName;   break;
  2307.     case PMSGID_LOCK:
  2308.       NamePart = (UBYTE **) &TN->tn_LockName; break;
  2309.     default:
  2310.       return TRUE;
  2311.   }
  2312.   
  2313.   if (!NamePart || !*NamePart) return FALSE;  
  2314.   strcpy((UBYTE *)&TmpPath, TN->tn_CurDirName);
  2315.  
  2316.   if (!AddPart((UBYTE *)&TmpPath, FilePart(*NamePart), TMP_BUF_LEN))
  2317.     return FALSE;
  2318.  
  2319.   MEM_FreeVec(*NamePart);
  2320.   *NamePart = MEM_StrToVec((UBYTE *)&TmpPath);
  2321.  
  2322.   if (*NamePart) return TRUE; else return FALSE;  
  2323. }
  2324.  
  2325. /* Note: The following ARTL_Find#? routines will always ignore
  2326.          TrackerNodes that are not in use. This is to avoid the
  2327.          chance that a clash will happen if two resources ever
  2328.          share the same memory space (at different times). For
  2329.          example, if task "A" closes a filehandle then task "B"
  2330.          opens a new filehandle, it's possible that the new
  2331.          filehandle will share the same memory space as the old
  2332.          one, even though they are two separate file handles. */
  2333.  
  2334. LPROTO struct TrackerNode *ARTL_FindLibTN_ViaLibName( struct List *TL,
  2335.   UBYTE *LibName )
  2336. {
  2337.   /*********************************************************************
  2338.    *
  2339.    * ARTL_FindLibTN_ViaLibName()
  2340.    *
  2341.    * Find a TrackerNode in a TrackerList via a library name.
  2342.    *
  2343.    *********************************************************************
  2344.    *
  2345.    */
  2346.  
  2347.   register struct TrackerNode *TN;
  2348.   
  2349.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2350.        TN->tn_Node.ln_Succ ;
  2351.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2352.   {
  2353.     if ((TN->tn_ID == PMSGID_OPENLIBRARY) &&
  2354.         (Stricmp(LibName, TN->tn_LibName) == 0) &&
  2355.          TN->tn_InUse)
  2356.     {
  2357.       return TN;
  2358.     }
  2359.   }
  2360.   return NULL;
  2361. }
  2362.  
  2363. LPROTO struct TrackerNode *ARTL_FindLibTN_ViaLibBase( struct List *TL,
  2364.   struct Library *LibBase )
  2365. {
  2366.   /*********************************************************************
  2367.    *
  2368.    * ARTL_FindLibTN_ViaLibBase()
  2369.    *
  2370.    * Find a TrackerNode in a TrackerList via a library base pointer.
  2371.    *
  2372.    *********************************************************************
  2373.    *
  2374.    */
  2375.  
  2376.   register struct TrackerNode *TN;
  2377.   
  2378.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2379.        TN->tn_Node.ln_Succ ;
  2380.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2381.   {
  2382.     if ((TN->tn_ID == PMSGID_OPENLIBRARY) &&
  2383.         (LibBase == TN->tn_LibBase) &&
  2384.         TN->tn_InUse)
  2385.     {
  2386.       return TN;
  2387.     }
  2388.   }
  2389.   return NULL;
  2390. }
  2391.  
  2392. LPROTO struct TrackerNode *ARTL_FindDevTN_ViaIOReq( struct List *TL,
  2393.   struct IORequest *IOReq )
  2394. {
  2395.   /*********************************************************************
  2396.    *
  2397.    * ARTL_FindDevTN_ViaIOReq()
  2398.    *
  2399.    * Find a TrackerNode in a TrackerList via a device IORequest pointer.
  2400.    *
  2401.    *********************************************************************
  2402.    *
  2403.    */
  2404.  
  2405.   register struct TrackerNode *TN;
  2406.   
  2407.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2408.        TN->tn_Node.ln_Succ;
  2409.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2410.   {
  2411.     if ((TN->tn_ID == PMSGID_OPENDEVICE) &&
  2412.         (IOReq == TN->tn_DevIOReq) &&
  2413.         TN->tn_InUse)
  2414.     {
  2415.       return TN;
  2416.     }
  2417.   }
  2418.   return NULL;
  2419. }
  2420.  
  2421. LPROTO struct TrackerNode *ARTL_FindDevTN_ViaDevName( struct List *TL,
  2422.   UBYTE *DevName )
  2423. {
  2424.   /*********************************************************************
  2425.    *
  2426.    * FindDevTN_Devname()
  2427.    *
  2428.    * Find a TrackerNode in a TrackerList via Device name.
  2429.    *
  2430.    *********************************************************************
  2431.    *
  2432.    */
  2433.  
  2434.   register struct TrackerNode *TN;
  2435.   
  2436.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2437.        TN->tn_Node.ln_Succ;
  2438.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2439.   {
  2440.     if ((TN->tn_ID == PMSGID_OPENDEVICE) &&
  2441.         (Stricmp(DevName, TN->tn_DevName) == 0) &&
  2442.         TN->tn_InUse)
  2443.     {
  2444.       return TN;
  2445.     }
  2446.   }
  2447.   return NULL;
  2448. }
  2449.  
  2450. LPROTO struct TrackerNode *ARTL_FindFontTN_ViaTextFont( struct List *TL,
  2451.   struct TextFont *TF )
  2452. {
  2453.   /*********************************************************************
  2454.    *
  2455.    * ARTL_FindFontTN_ViaTextFont()
  2456.    *
  2457.    *********************************************************************
  2458.    *
  2459.    */
  2460.  
  2461.   register struct TrackerNode *TN;
  2462.   
  2463.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2464.        TN->tn_Node.ln_Succ;
  2465.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2466.   {
  2467.     if (TN->tn_ID == PMSGID_OPENFONT)
  2468.     {
  2469.       if (TF == TN->tn_FontTextFont && TN->tn_InUse) return TN;
  2470.     }
  2471.   }
  2472.   return NULL;  
  2473. }
  2474.  
  2475. LPROTO struct TrackerNode *ARTL_FindLockTN_ViaLock( struct List *TL,
  2476.   BPTR Lk )
  2477. {
  2478.   /*********************************************************************
  2479.    *
  2480.    * ARTL_FindLockTN_ViaLock()
  2481.    *
  2482.    *********************************************************************
  2483.    *
  2484.    */
  2485.  
  2486.   register struct TrackerNode *TN;
  2487.   
  2488.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2489.        TN->tn_Node.ln_Succ;
  2490.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2491.   {
  2492.     if (TN->tn_ID == PMSGID_LOCK)
  2493.     {
  2494.       if (Lk == TN->tn_Lock && TN->tn_InUse) return TN;
  2495.     }
  2496.   }
  2497.   return NULL;      
  2498. }
  2499.  
  2500. LPROTO struct TrackerNode *ARTL_FindFileHandleTN_ViaFH( struct List *TL,
  2501.   BPTR FH )
  2502. {
  2503.   /*********************************************************************
  2504.    *
  2505.    * ARTL_FindFileHandleTN_ViaFH()
  2506.    *
  2507.    *********************************************************************
  2508.    *
  2509.    */
  2510.  
  2511.   register struct TrackerNode *TN;
  2512.   
  2513.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2514.        TN->tn_Node.ln_Succ;
  2515.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2516.   {
  2517.     if ((TN->tn_ID == PMSGID_OPEN) || (TN->tn_ID == PMSGID_OPENFROMLOCK))
  2518.     {
  2519.       if (FH == TN->tn_FH && TN->tn_InUse) return TN;
  2520.     }
  2521.   }
  2522.   return NULL;      
  2523. }
  2524.  
  2525. LPROTO void ARTL_UnlinkTN( struct TrackerNode *TN )
  2526. {
  2527.   /*********************************************************************
  2528.    *
  2529.    * ARTL_UnlinkTN()
  2530.    *
  2531.    * Unlink a TrackerNode from a TrackerList.
  2532.    *
  2533.    *********************************************************************
  2534.    *
  2535.    */
  2536.  
  2537.   if ((TN->tn_Node.ln_Succ == NULL) || (TN->tn_Node.ln_Pred == NULL))
  2538.     return;
  2539.   Remove((struct Node *)TN);
  2540.   TN->tn_Node.ln_Succ = NULL;
  2541.   TN->tn_Node.ln_Pred = NULL;
  2542. }
  2543.  
  2544. LPROTO void ARTL_FreeTL( struct List *TL )
  2545. {
  2546.   /*********************************************************************
  2547.    *
  2548.    * ARTL_FreeTL()
  2549.    *
  2550.    * Free an entire TrackerList.
  2551.    *
  2552.    *********************************************************************
  2553.    *
  2554.    */
  2555.  
  2556.   register struct TrackerNode *TN, *TmpTN;
  2557.   
  2558.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2559.        TN->tn_Node.ln_Succ ;)
  2560.   {
  2561.     TmpTN = (struct TrackerNode *) TN->tn_Node.ln_Succ;
  2562.     ARTL_FreeTN(TN); TN = TmpTN;
  2563.   }
  2564.   NewList(TL);  
  2565. }
  2566.  
  2567. LPROTO void ARTL_UpdateTL( struct List *TL )
  2568. {
  2569.   /*********************************************************************
  2570.    *
  2571.    * ARTL_UpdateTL()
  2572.    *
  2573.    * Update the GUI tracker lister using a TrackerLister structure.
  2574.    *
  2575.    *********************************************************************
  2576.    *
  2577.    */
  2578.  
  2579.   register struct TrackerNode *TN;
  2580.   register ULONG TrackMode = ARTL_Get_TrackMode();
  2581.  
  2582.   GUI_Act_List_Clear(OID_MAIN_TRACKERLIST);
  2583.   GUI_Set_List_Quiet(OID_MAIN_TRACKERLIST, TRUE);
  2584.  
  2585.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2586.        TN->tn_Node.ln_Succ;
  2587.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2588.   { 
  2589.     if (cfg_ShowUnusedResources == FALSE && TN->tn_InUse == FALSE)
  2590.       continue;
  2591.  
  2592.     if (TrackMode == TRACKMODE_LIBRARIES && TN->tn_ID == PMSGID_OPENLIBRARY)
  2593.       GUI_Act_List_InsertABC(OID_MAIN_TRACKERLIST, TN);
  2594.     else if (TrackMode == TRACKMODE_DEVICES && TN->tn_ID == PMSGID_OPENDEVICE)
  2595.       GUI_Act_List_InsertABC(OID_MAIN_TRACKERLIST, TN);
  2596.     else if (TrackMode == TRACKMODE_FONTS && (TN->tn_ID == PMSGID_OPENFONT))
  2597.       GUI_Act_List_InsertABC(OID_MAIN_TRACKERLIST, TN);
  2598.     else if ((TrackMode == TRACKMODE_FILEHANDLES) &&
  2599.               (TN->tn_ID == PMSGID_OPEN) || (TN->tn_ID == PMSGID_OPENFROMLOCK))
  2600.       GUI_Act_List_InsertABC(OID_MAIN_TRACKERLIST, TN);
  2601.     else if (TrackMode == TRACKMODE_LOCKS && TN->tn_ID == PMSGID_LOCK)
  2602.       GUI_Act_List_InsertABC(OID_MAIN_TRACKERLIST, TN);
  2603.   }
  2604.   GUI_Set_List_Quiet(OID_MAIN_TRACKERLIST, FALSE);
  2605. }
  2606.  
  2607. LPROTO ULONG ARTL_CountTL( struct List *TL, LONG ID )
  2608. {
  2609.   /*********************************************************************
  2610.    *
  2611.    * ARTL_CountTL()
  2612.    *
  2613.    * Count the amount of TrackerNodes in a TrackerList, using a
  2614.    * specific AppNode ID. Use PMSGID_ALL to count all nodes.
  2615.    *
  2616.    * Notes
  2617.    * -----
  2618.    *
  2619.    * You may pass PMSGID_ALL to the ID parameter.
  2620.    *
  2621.    *********************************************************************
  2622.    *
  2623.    */
  2624.  
  2625.   register struct TrackerNode *TN;
  2626.   register ULONG Cnt = 0;
  2627.   
  2628.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2629.        TN->tn_Node.ln_Succ;
  2630.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2631.   {
  2632.     if ((TN->tn_ID == ID) || (ID == PMSGID_ALL)) Cnt++;
  2633.   }
  2634.   return Cnt;
  2635. }
  2636.  
  2637. LPROTO ULONG ARTL_CountTNsInUse( struct List *TL )
  2638. {
  2639.   /*********************************************************************
  2640.    *
  2641.    * ARTL_CountTNsInUse()
  2642.    *
  2643.    * Count the amount of TrackerNodes in a TrackerList that
  2644.    * currently have their TrackerNodes->tn_InUse flag set.
  2645.    *
  2646.    *********************************************************************
  2647.    *
  2648.    */
  2649.  
  2650.   register ULONG Cnt = 0;
  2651.   register struct TrackerNode *TN;
  2652.  
  2653.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2654.        TN->tn_Node.ln_Succ;
  2655.        TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2656.   {
  2657.     if (TN->tn_InUse) Cnt++;
  2658.   }
  2659.   return Cnt;
  2660. }
  2661.  
  2662. GPROTO ULONG ARTL_ClearUnusedTNs( struct List *TL )
  2663. {
  2664.   /*********************************************************************
  2665.    *
  2666.    * ARTL_ClearUnusedTNs()
  2667.    *
  2668.    *********************************************************************
  2669.    *
  2670.    */
  2671.  
  2672.   register ULONG FreedTNCnt = 0;
  2673.   register struct TrackerNode *TN, *NextTN;
  2674.  
  2675.   for (TN = (struct TrackerNode *) TL->lh_Head;
  2676.        TN->tn_Node.ln_Succ;)
  2677.   {
  2678.     NextTN = (struct TrackerNode *) TN->tn_Node.ln_Succ;
  2679.     
  2680.     if (!TN->tn_InUse)
  2681.     {
  2682.       ARTL_UnlinkTN(TN); ARTL_FreeTN(TN);
  2683.       FreedTNCnt++;
  2684.     }   
  2685.     TN = NextTN;
  2686.   }
  2687.   return FreedTNCnt;
  2688. }
  2689.  
  2690.  
  2691. /**** ATRL misc ************************************************************/
  2692.  
  2693. LPROTO void ARTL_FindAppsUsingRes( struct TrackerNode *TNToFnd,
  2694.   struct AppList *AL )
  2695. {
  2696.   /*********************************************************************
  2697.    *
  2698.    * ARTL_FindAppsUsingRes()
  2699.    *
  2700.    * This routine will try to locate all AppNodes using a particular
  2701.    * resource. This resource is represented by the TrackerNode
  2702.    * structure. The details of the resulting AppNodes are inserted into
  2703.    * the "APPUSING" lister.
  2704.    *
  2705.    *********************************************************************
  2706.    *
  2707.    */
  2708.  
  2709.   register struct AppNode *AN;
  2710.  
  2711.   ARTL_LockAL(AL);
  2712.  
  2713.   for (AN = (struct AppNode *) ARTL->al_List.lh_Head;
  2714.        AN->an_Node.ln_Succ;
  2715.        AN = (struct AppNode *) AN->an_Node.ln_Succ)
  2716.   {
  2717.     register struct TrackerNode *TN;
  2718.  
  2719.     for (TN = (struct TrackerNode *) AN->an_TrackerList.lh_Head;
  2720.          TN->tn_Node.ln_Succ;
  2721.          TN = (struct TrackerNode *) TN->tn_Node.ln_Succ)
  2722.     {
  2723.       if ((TNToFnd->tn_ID == TN->tn_ID) && TN->tn_InUse)
  2724.       {
  2725.         register LONG CmpResult = -1;
  2726.  
  2727.         switch(TN->tn_ID)
  2728.         {
  2729.           case PMSGID_OPENLIBRARY:
  2730.             CmpResult = Stricmp(TNToFnd->tn_LibName, TN->tn_LibName);
  2731.             break;
  2732.           case PMSGID_OPENDEVICE:
  2733.             CmpResult = Stricmp(TNToFnd->tn_DevName, TN->tn_DevName);
  2734.             break;
  2735.           case PMSGID_OPENFONT:
  2736.             CmpResult = Stricmp(TNToFnd->tn_FontName, TN->tn_FontName);
  2737.             break;
  2738.  
  2739.           case PMSGID_OPENFROMLOCK:
  2740.           case PMSGID_OPEN:
  2741.           {
  2742.             CmpResult = -1; /* Assume they're different */
  2743.  
  2744.             if (TNToFnd->tn_FHName && TN->tn_FHName)
  2745.             {
  2746.               register BPTR Lock1 = 0, Lock2 = 0;
  2747.                             
  2748.               if ((Lock1 = Lock(TNToFnd->tn_FHName, SHARED_LOCK)) &&
  2749.                   (Lock2 = Lock(TN->tn_FHName, SHARED_LOCK)))
  2750.               {
  2751.                 if (SameLock(Lock1, Lock2) == LOCK_SAME) CmpResult = 0;
  2752.               }   
  2753.               if (Lock1) UnLock(Lock1);
  2754.               if (Lock2) UnLock(Lock2);             
  2755.             }
  2756.             break;
  2757.           }
  2758.  
  2759.           case PMSGID_LOCK:
  2760.           {
  2761.             CmpResult = -1; /* Assume they're different */
  2762.  
  2763.             if (TNToFnd->tn_LockName && TN->tn_LockName)
  2764.             {
  2765.               register BPTR Lock1 = 0, Lock2 = 0;
  2766.                             
  2767.               if ((Lock1 = Lock(TNToFnd->tn_FHName, SHARED_LOCK)) &&
  2768.                   (Lock2 = Lock(TN->tn_FHName, SHARED_LOCK)))
  2769.               {
  2770.                 if (SameLock(Lock1, Lock2) == LOCK_SAME) CmpResult = 0;
  2771.               }
  2772.               if (Lock1) UnLock(Lock1);
  2773.               if (Lock2) UnLock(Lock2);             
  2774.             }
  2775.             break;
  2776.           }
  2777.         }
  2778.           
  2779.         if (CmpResult == 0)
  2780.         {
  2781.           register UBYTE *AppName = AN->an_CmdName;
  2782.           if (!AppName) AppName = AN->an_TaskName;
  2783.           GUI_Act_List_InsertABC(OID_APPUSING_LISTVIEW, FilePart(AppName));
  2784.         }
  2785.       }
  2786.     } /* for(;;) */
  2787.   } /* for(;;) */
  2788.   ARTL_UnlockAL(AL);
  2789. }
  2790.  
  2791. LPROTO ULONG ARTL_CountList( struct List *L )
  2792. {
  2793.   /*********************************************************************
  2794.    *
  2795.    * ARTL_CountList()
  2796.    *
  2797.    * A generic list node count function. Suitable for all exec style
  2798.    * linked lists.
  2799.    *
  2800.    *********************************************************************
  2801.    *
  2802.    */
  2803.  
  2804.   register struct Node *N;
  2805.   register ULONG Cnt = 0;
  2806.  
  2807.   for (N = L->lh_Head; N->ln_Succ; N = N->ln_Succ)
  2808.     Cnt++;
  2809.   return Cnt;
  2810. }
  2811.  
  2812. /***************************************************************************/
  2813. /* Hooks for the left lister (aka AppLister) */
  2814. /***************************************************************************/
  2815.  
  2816. GPROTO void ARTL_AppListKillFunc( register __a2 APTR Pool,
  2817.   register __a1 struct AppNode *AN )
  2818. {
  2819.   ARTL_FreeAN(AN);
  2820. }
  2821.  
  2822. GPROTO struct AppNode *ARTL_AppListMakeFunc( register __a2 APTR Pool,
  2823.   register __a1 struct AppNode *AN )
  2824. {
  2825.   return ARTL_CloneAN(AN); /* Clone the AppNode */
  2826. }
  2827.  
  2828. GPROTO LONG ARTL_AppListShowFunc( register __a2 UBYTE **ColumnArray,
  2829.   register __a1 struct AppNode *AN )
  2830.   if (AN)
  2831.   {
  2832.     ColumnArray[0] = AN->an_TaskName;
  2833.  
  2834.     if (AN->an_CmdName) ColumnArray[0] = AN->an_CmdName;
  2835.  
  2836.     if (ColumnArray[0][0] == 0)
  2837.       ColumnArray[0] = "(Internal Error: Hook got empty string)";
  2838.     else if (cfg_RemovePaths)
  2839.       ColumnArray[0] = FilePart(ColumnArray[0]);
  2840.  
  2841.     switch(AN->an_TaskType)
  2842.     {
  2843.       case NT_TASK:    ColumnArray[1] = STR_Get(SID_TASK);    break;
  2844.       case NT_PROCESS: ColumnArray[1] = STR_Get(SID_PROCESS); break;
  2845.       default:         ColumnArray[1] = STR_Get(SID_UNKNOWN); break;
  2846.     }
  2847.  
  2848.     switch(AN->an_Status)
  2849.     {
  2850.       default:
  2851.       case AN_STATUS_UNKNOWN: ColumnArray[2] = STR_Get(SID_UNKNOWN); break;
  2852.       case AN_STATUS_ALIVE:   ColumnArray[2] = STR_Get(SID_ALIVE);   break;
  2853.       case AN_STATUS_DEAD:    ColumnArray[2] = STR_Get(SID_DEAD);    break;
  2854.     }
  2855.   }
  2856.   else
  2857.   {
  2858.     ColumnArray[0] = STR_Get(SID_APPNAME);
  2859.     ColumnArray[1] = STR_Get(SID_TYPE);
  2860.     ColumnArray[2] = STR_Get(SID_STATUS);
  2861.   }
  2862.   return 0;
  2863. }
  2864.  
  2865. GPROTO LONG ARTL_AppListSortFunc( register __a1 struct AppNode *AN1,
  2866.   register __a2 struct AppNode *AN2 )
  2867. {
  2868.   return Stricmp(AN1->an_TaskName, AN2->an_TaskName);
  2869. }
  2870.  
  2871. struct Hook ARTL_AppListMakeHook =
  2872.   { { NULL, NULL }, (void *) ARTL_AppListMakeFunc, NULL, NULL };
  2873. struct Hook ARTL_AppListKillHook =
  2874.   { { NULL, NULL }, (void *) ARTL_AppListKillFunc, NULL, NULL };
  2875. struct Hook ARTL_AppListShowHook =
  2876.   { { NULL, NULL }, (void *) ARTL_AppListShowFunc, NULL, NULL };
  2877. struct Hook ARTL_AppListSortHook =
  2878.   { { NULL, NULL }, (void *) ARTL_AppListSortFunc, NULL, NULL };
  2879.  
  2880. /***************************************************************************/
  2881. /* Hooks for the right lister (aka TrackerLister) */
  2882. /***************************************************************************/
  2883.  
  2884. GPROTO void ARTL_TrackerListKillFunc( register __a2 APTR Pool,
  2885.   register __a1 struct TrackerNode *TN )
  2886. {
  2887.   ARTL_FreeTN(TN); /* Free the clone allocated by the make hook. */
  2888. }
  2889.  
  2890. GPROTO struct TrackerNode *ARTL_TrackerListMakeFunc(
  2891.   register __a2 APTR Pool,
  2892.   register __a1 struct TrackerNode *TN )
  2893. {
  2894.   /* We must clone the tracker node so the ARTL-Handler doesn't
  2895.      rip the memory from under MUI. */
  2896.   
  2897.   return ARTL_CloneTN(TN);
  2898. }
  2899.  
  2900. GPROTO LONG ARTL_TrackerListShowFunc( register __a2 UBYTE **ColumnArray,
  2901.   register __a1 struct TrackerNode *TN )
  2902. {
  2903.   if (TN)
  2904.   {
  2905.     sprintf((UBYTE *) &TN->tn_OpenCntTxt, "%ld", TN->tn_OpenCnt);
  2906.     ColumnArray[1] = (UBYTE *) &TN->tn_OpenCntTxt;
  2907.  
  2908.     switch(TN->tn_ID)
  2909.     {
  2910.       case PMSGID_OPENLIBRARY:
  2911.         ColumnArray[0] = TN->tn_LibName;
  2912.         break;
  2913.       case PMSGID_OPENDEVICE:
  2914.         sprintf((UBYTE *)&TN->tn_DevUnitNumTxt, "%ld", TN->tn_DevUnitNum);
  2915.         ColumnArray[0] = TN->tn_DevName;
  2916.         ColumnArray[1] = (UBYTE *) &TN->tn_DevUnitNumTxt;
  2917.         break;
  2918.       case PMSGID_OPENFONT:
  2919.         ColumnArray[0] = TN->tn_FontName;
  2920.         break;
  2921.  
  2922.       case PMSGID_OPENFROMLOCK:
  2923.       case PMSGID_OPEN:
  2924.       {
  2925.         if (!TN->tn_FHName || strlen(TN->tn_FHName) == 0)
  2926.           ColumnArray[0] = "(no name)";
  2927.         else
  2928.           ColumnArray[0] = TN->tn_FHName;
  2929.  
  2930.         switch(TN->tn_FHMode)
  2931.         {
  2932.           case MODE_OLDFILE:   ColumnArray[1] = "Read";       break;
  2933.           case MODE_NEWFILE:   ColumnArray[1] = "Write";      break;
  2934.           case MODE_READWRITE: ColumnArray[1] = "Read/Write"; break;
  2935.           default:             ColumnArray[1] = "Unknown";    break;
  2936.         }       
  2937.         break;
  2938.       }
  2939.  
  2940.       case PMSGID_LOCK:
  2941.       {
  2942.         if (!TN->tn_LockName || strlen(TN->tn_LockName) == 0)
  2943.           ColumnArray[0] = "(no name)";
  2944.         else
  2945.           ColumnArray[0] = TN->tn_LockName;
  2946.  
  2947.         switch(TN->tn_LockMode)
  2948.         {
  2949.           case SHARED_LOCK:    ColumnArray[1] = "Shared";    break;
  2950.           case EXCLUSIVE_LOCK: ColumnArray[1] = "Exclusive"; break;
  2951.           default:             ColumnArray[1] = "Unknown";   break;
  2952.         }       
  2953.         break;
  2954.       }
  2955.  
  2956.       default:
  2957.         ColumnArray[0] = "Internal Error: Unknown Trackernode ID!";
  2958.         break;
  2959.     }
  2960.  
  2961.     if (TN->tn_InUse) ColumnArray[2] = "Yes";
  2962.     else ColumnArray[2] = "No";
  2963.   }
  2964.   else  /* Print lister title */
  2965.   {       
  2966.     switch(ARTL_Get_TrackMode())
  2967.     {
  2968.       case TRACKMODE_LIBRARIES:
  2969.         ColumnArray[0] = STR_Get(SID_LISTTITLE_LIBRARIES);
  2970.         ColumnArray[1] = STR_Get(SID_LISTTITLE_OPENCOUNT);
  2971.         ColumnArray[2] = "\33bIn use?";
  2972.         break;
  2973.       case TRACKMODE_DEVICES:
  2974.         ColumnArray[0] = STR_Get(SID_LISTTITLE_DEVICES);
  2975.         ColumnArray[1] = "\33bUnit Num";
  2976.         ColumnArray[2] = "\33bIn use?";
  2977.         break;
  2978.       case TRACKMODE_FONTS:
  2979.         ColumnArray[0] = STR_Get(SID_LISTTITLE_FONTS);
  2980.         ColumnArray[1] = STR_Get(SID_LISTTITLE_OPENCOUNT);
  2981.         ColumnArray[2] = "\33bIn use?";
  2982.         break;
  2983.       case TRACKMODE_FILEHANDLES:
  2984.         ColumnArray[0] = "\33bFile handles";
  2985.         ColumnArray[1] = "\33bMode";
  2986.         ColumnArray[2] = "\33bIn use?";
  2987.         break;
  2988.       case TRACKMODE_LOCKS:
  2989.         ColumnArray[0] = "\33bLocks";
  2990.         ColumnArray[1] = "\33bMode";
  2991.         ColumnArray[2] = "\33bIn use?";
  2992.         break;
  2993.       default:
  2994.         ColumnArray[0] = "\33bInternal Error: Unknown TrackMode ID!!!";
  2995.         ColumnArray[1] = "";
  2996.         ColumnArray[2] = "";
  2997.         break;
  2998.     }
  2999.  
  3000.   }
  3001.   return 0;
  3002. }
  3003.  
  3004. GPROTO LONG ARTL_TrackerListSortFunc(
  3005.   register __a1 struct TrackerNode *TN1,
  3006.   register __a2 struct TrackerNode *TN2 )
  3007. {
  3008.   register LONG result;
  3009.  
  3010.   switch(TN1->tn_ID)
  3011.   {
  3012.     case PMSGID_OPENLIBRARY:
  3013.       result = Stricmp(TN1->tn_LibName, TN2->tn_LibName);
  3014.       break;
  3015.     case PMSGID_OPENDEVICE:
  3016.       result = Stricmp(TN1->tn_DevName, TN2->tn_DevName);
  3017.       break;
  3018.     case PMSGID_OPENFONT:
  3019.       result = Stricmp(TN1->tn_FontName, TN2->tn_FontName);
  3020.       break;
  3021.     default:
  3022.       result = 0;
  3023.       break;
  3024.   }
  3025.   return result; 
  3026. }
  3027.  
  3028. struct Hook ARTL_TrackerListMakeHook =
  3029.   { { NULL, NULL }, (void *) ARTL_TrackerListMakeFunc, NULL, NULL };
  3030. struct Hook ARTL_TrackerListKillHook =
  3031.   { { NULL, NULL }, (void *) ARTL_TrackerListKillFunc, NULL, NULL };
  3032. struct Hook ARTL_TrackerListShowHook =
  3033.   { { NULL, NULL }, (void *) ARTL_TrackerListShowFunc, NULL, NULL };
  3034. struct Hook ARTL_TrackerListSortHook =
  3035.   { { NULL, NULL }, (void *) ARTL_TrackerListSortFunc, NULL, NULL };
  3036.  
  3037.   /*********************************************************************
  3038.    *
  3039.    *
  3040.    *
  3041.    *********************************************************************
  3042.    *
  3043.    */
  3044.  
  3045.  
  3046.